Decompiled source of Runeborn v0.4.2

plugins/RustyHeathensRuneborn/RustyHeathensRuneborn.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using UnityEngine;

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

[BepInPlugin("com.rustylasergaming.runeborn", "Rusty Heathens Runeborn", "0.4.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
public sealed class RunebornPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "com.rustylasergaming.runeborn";

	public const string PluginName = "Rusty Heathens Runeborn";

	public const string PluginVersion = "0.4.2";

	internal static ConfigEntry<KeyboardShortcut> MenuKey;

	internal static ConfigEntry<KeyboardShortcut> AdminMenuKey;

	internal static ConfigEntry<bool> ServerReminderEnabledEntry;

	internal static ConfigEntry<bool> RaidWarningsEnabledEntry;

	private Harmony _harmony;

	private bool _menuOpen;

	private bool _adminMenuOpen;

	private Rect _windowRect = new Rect(40f, 80f, 560f, 700f);

	private Rect _adminWindowRect = new Rect(620f, 80f, 520f, 640f);

	private Vector2 _scrollPosition = Vector2.zero;

	private Vector2 _adminScrollPosition = Vector2.zero;

	private GUISkin _runebornSkin;

	private GUIStyle _sectionHeaderStyle;

	private GUIStyle _subHeaderStyle;

	private GUIStyle _mutedLabelStyle;

	private GUIStyle _goodLabelStyle;

	private GUIStyle _warningLabelStyle;

	private GUIStyle _accentLabelStyle;

	private GUIStyle _selectedButtonStyle;

	private GUIStyle _lockedButtonStyle;

	private GUIStyle _disabledButtonStyle;

	private GUIStyle _closeButtonStyle;

	private GUIStyle _hudTitleStyle;

	private GUIStyle _hudLabelStyle;

	private readonly List<Texture2D> _guiTextures = new List<Texture2D>();

	private bool _showAdminDiagnostics;

	private int _playerMenuTab;

	private int _adminMenuTab;

	private CursorLockMode _previousCursorLock;

	private bool _previousCursorVisible;

	internal static RunebornPlugin Instance { get; private set; }

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

	private void OnDestroy()
	{
		Harmony harmony = _harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		if ((Object)(object)_runebornSkin != (Object)null)
		{
			Object.Destroy((Object)(object)_runebornSkin);
			_runebornSkin = null;
		}
		foreach (Texture2D guiTexture in _guiTextures)
		{
			if ((Object)(object)guiTexture != (Object)null)
			{
				Object.Destroy((Object)(object)guiTexture);
			}
		}
		_guiTextures.Clear();
	}

	private void Update()
	{
		//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)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		RunebornAdminEventMessages.EnsureRegistered();
		RunebornBuffSlotSyncFoundation.EnsureRegistered();
		RunebornBuffSlotSyncFoundation.UpdateLateJoinRequest();
		RunebornBuffAvailabilitySync.EnsureRegistered();
		RunebornBuffAvailabilitySync.UpdateLateJoinRequest();
		RunebornBuffStatusEffects.UpdateLocalPlayerEffects();
		KeyboardShortcut value = MenuKey.Value;
		if (((KeyboardShortcut)(ref value)).IsDown())
		{
			ToggleMenu();
		}
		value = AdminMenuKey.Value;
		if (((KeyboardShortcut)(ref value)).IsDown())
		{
			if (RunebornAdminTools.IsLocalAdmin())
			{
				ToggleAdminMenu();
			}
			else
			{
				ShowLocalCenterMessage("Admin menu is locked.");
			}
		}
	}

	private void BindConfig()
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		MenuKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "OpenPlayerHelpMenu", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Open or close the Rusty Heathens player help menu.");
		AdminMenuKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "OpenAdminMenu", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Open or close the Rusty Heathens admin menu. Admin SteamID only.");
		ServerReminderEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("Admin Settings", "ServerReminderEnabled", true, "Admin-controlled toggle for the Rusty Heathens server reminder message.");
		RaidWarningsEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("Admin Settings", "RaidWarningsEnabled", true, "Admin-controlled toggle for Rusty Heathens raid warning messages.");
		ApplyAdminSettingsToRuntime();
	}

	internal static void ApplyAdminSettingsToRuntime()
	{
		if (ServerReminderEnabledEntry != null)
		{
			RunebornServerReminder.ServerReminderEnabled = ServerReminderEnabledEntry.Value;
		}
		if (RaidWarningsEnabledEntry != null)
		{
			RunebornRaidWarnings.RaidWarningsEnabled = RaidWarningsEnabledEntry.Value;
		}
	}

	private static void ShowLocalCenterMessage(string text)
	{
		if ((Object)(object)Player.m_localPlayer == (Object)null)
		{
			return;
		}
		try
		{
			((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null);
		}
		catch
		{
		}
	}

	private void ToggleMenu()
	{
		_menuOpen = !_menuOpen;
		ApplyCursorStateForOpenMenus();
	}

	private void ToggleAdminMenu()
	{
		_adminMenuOpen = !_adminMenuOpen;
		ApplyCursorStateForOpenMenus();
	}

	private void ApplyCursorStateForOpenMenus()
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		if (_menuOpen || _adminMenuOpen)
		{
			_previousCursorLock = Cursor.lockState;
			_previousCursorVisible = Cursor.visible;
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
		}
		else
		{
			Cursor.lockState = _previousCursorLock;
			Cursor.visible = _previousCursorVisible;
		}
	}

	private void OnGUI()
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Expected O, but got Unknown
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Expected O, but got Unknown
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		GUISkin skin = GUI.skin;
		EnsureRunebornGuiSkin();
		if ((Object)(object)_runebornSkin != (Object)null)
		{
			GUI.skin = _runebornSkin;
		}
		try
		{
			if (_menuOpen)
			{
				_windowRect = GUI.Window(928417, _windowRect, new WindowFunction(DrawWindow), "Rusty Heathens", GUI.skin.window);
			}
			if (_adminMenuOpen)
			{
				if (RunebornAdminTools.IsLocalAdmin())
				{
					_adminWindowRect = GUI.Window(928418, _adminWindowRect, new WindowFunction(DrawAdminWindow), "Rusty Heathens Admin", GUI.skin.window);
					return;
				}
				_adminMenuOpen = false;
				ApplyCursorStateForOpenMenus();
			}
		}
		finally
		{
			GUI.skin = skin;
		}
	}

	private void DrawActiveBuffHud()
	{
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)Player.m_localPlayer == (Object)null)
		{
			return;
		}
		List<string> list = new List<string>();
		if (RunebornServerComfort.IsRustyRestedActiveForLocalPlayer())
		{
			list.Add("<color=#D9A441>[R]</color> Rusty Buff");
		}
		if (RunebornServerComfort.IsSeppyBuffActiveForLocalPlayer())
		{
			list.Add("<color=#D9A441>[S]</color> Seppy Buff");
		}
		if (RunebornServerComfort.IsXpertBuffActiveForLocalPlayer())
		{
			list.Add("<color=#D9A441>[X]</color> Xpert Buff");
		}
		if (RunebornServerComfort.IsChaosBringerBuffActiveForLocalPlayer())
		{
			list.Add("<color=#D9A441>[C]</color> Chaos Bringer");
		}
		if (RunebornServerComfort.IsWitchyBuffActiveForLocalPlayer())
		{
			list.Add("<color=#D9A441>[W]</color> Witchy Buff");
		}
		if (list.Count != 0)
		{
			float num = 42f + (float)list.Count * 22f;
			float num2 = (float)Screen.width - 230f - 18f;
			float num3 = Mathf.Max(18f, (float)Screen.height - num - 18f);
			float num4 = Mathf.Clamp(220f, 18f, num3);
			GUI.Box(new Rect(num2, num4, 230f, num), GUIContent.none, GUI.skin.box);
			GUI.Label(new Rect(num2 + 8f, num4 + 6f, 214f, 24f), "ACTIVE BUFFS", _hudTitleStyle ?? GUI.skin.label);
			for (int i = 0; i < list.Count; i++)
			{
				GUI.Label(new Rect(num2 + 12f, num4 + 34f + (float)i * 22f, 206f, 22f), list[i], _hudLabelStyle ?? GUI.skin.label);
			}
		}
	}

	private void DrawWindow(int windowId)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		if (GUI.Button(new Rect(((Rect)(ref _windowRect)).width - 34f, 6f, 26f, 22f), "X", _closeButtonStyle ?? GUI.skin.button))
		{
			ToggleMenu();
			return;
		}
		GUILayout.Space(8f);
		_scrollPosition = GUILayout.BeginScrollView(_scrollPosition, false, true, (GUILayoutOption[])(object)new GUILayoutOption[2]
		{
			GUILayout.Width(((Rect)(ref _windowRect)).width - 28f),
			GUILayout.Height(((Rect)(ref _windowRect)).height - 52f)
		});
		DrawServerComfortMenuContent();
		GUILayout.EndScrollView();
		GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width - 42f, 30f));
	}

	private void DrawAdminWindow(int windowId)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		if (GUI.Button(new Rect(((Rect)(ref _adminWindowRect)).width - 34f, 6f, 26f, 22f), "X", _closeButtonStyle ?? GUI.skin.button))
		{
			ToggleAdminMenu();
			return;
		}
		GUILayout.Space(8f);
		_adminScrollPosition = GUILayout.BeginScrollView(_adminScrollPosition, false, true, (GUILayoutOption[])(object)new GUILayoutOption[2]
		{
			GUILayout.Width(((Rect)(ref _adminWindowRect)).width - 28f),
			GUILayout.Height(((Rect)(ref _adminWindowRect)).height - 52f)
		});
		DrawAdminMenuContent();
		GUILayout.EndScrollView();
		GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _adminWindowRect)).width - 42f, 30f));
	}

	private void EnsureRunebornGuiSkin()
	{
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0207: Unknown result type (might be due to invalid IL or missing references)
		//IL_020c: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0264: Unknown result type (might be due to invalid IL or missing references)
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_0287: Unknown result type (might be due to invalid IL or missing references)
		//IL_028c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_02af: Unknown result type (might be due to invalid IL or missing references)
		//IL_0331: Unknown result type (might be due to invalid IL or missing references)
		//IL_033e: Unknown result type (might be due to invalid IL or missing references)
		//IL_034b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0358: Unknown result type (might be due to invalid IL or missing references)
		//IL_0365: Unknown result type (might be due to invalid IL or missing references)
		//IL_0372: Unknown result type (might be due to invalid IL or missing references)
		//IL_037f: Unknown result type (might be due to invalid IL or missing references)
		//IL_038c: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_03bc: Expected O, but got Unknown
		//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ca: Expected O, but got Unknown
		//IL_0443: Unknown result type (might be due to invalid IL or missing references)
		//IL_0450: Unknown result type (might be due to invalid IL or missing references)
		//IL_045d: Unknown result type (might be due to invalid IL or missing references)
		//IL_046a: Unknown result type (might be due to invalid IL or missing references)
		//IL_047a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0484: Expected O, but got Unknown
		//IL_0488: Unknown result type (might be due to invalid IL or missing references)
		//IL_0492: Expected O, but got Unknown
		//IL_04a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ce: Expected O, but got Unknown
		//IL_051a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0528: Unknown result type (might be due to invalid IL or missing references)
		//IL_0536: Unknown result type (might be due to invalid IL or missing references)
		//IL_0544: Unknown result type (might be due to invalid IL or missing references)
		//IL_0562: Unknown result type (might be due to invalid IL or missing references)
		//IL_056c: Expected O, but got Unknown
		//IL_0572: Unknown result type (might be due to invalid IL or missing references)
		//IL_057c: Expected O, but got Unknown
		//IL_058e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0598: Expected O, but got Unknown
		//IL_05ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_05fe: Expected O, but got Unknown
		//IL_061b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0625: Expected O, but got Unknown
		//IL_0629: Unknown result type (might be due to invalid IL or missing references)
		//IL_0633: Expected O, but got Unknown
		//IL_06bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_06c6: Expected O, but got Unknown
		//IL_06e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0719: Unknown result type (might be due to invalid IL or missing references)
		//IL_0723: Expected O, but got Unknown
		//IL_072d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0737: Expected O, but got Unknown
		//IL_0751: Unknown result type (might be due to invalid IL or missing references)
		//IL_075b: Expected O, but got Unknown
		//IL_075e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0768: Expected O, but got Unknown
		//IL_0773: Unknown result type (might be due to invalid IL or missing references)
		//IL_079d: Unknown result type (might be due to invalid IL or missing references)
		//IL_07a7: Expected O, but got Unknown
		//IL_07aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_07b4: Expected O, but got Unknown
		//IL_07bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_07d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_07e0: Expected O, but got Unknown
		//IL_07eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0801: Unknown result type (might be due to invalid IL or missing references)
		//IL_080b: Expected O, but got Unknown
		//IL_0816: Unknown result type (might be due to invalid IL or missing references)
		//IL_082c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0836: Expected O, but got Unknown
		//IL_0841: Unknown result type (might be due to invalid IL or missing references)
		//IL_0857: Unknown result type (might be due to invalid IL or missing references)
		//IL_0861: Expected O, but got Unknown
		//IL_0890: Unknown result type (might be due to invalid IL or missing references)
		//IL_08a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_08b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_08be: Unknown result type (might be due to invalid IL or missing references)
		//IL_08c8: Expected O, but got Unknown
		//IL_08f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0909: Unknown result type (might be due to invalid IL or missing references)
		//IL_091b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0925: Unknown result type (might be due to invalid IL or missing references)
		//IL_092f: Expected O, but got Unknown
		//IL_095e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0970: Unknown result type (might be due to invalid IL or missing references)
		//IL_097a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0984: Expected O, but got Unknown
		//IL_09c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_09d1: Expected O, but got Unknown
		//IL_09d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_09de: Expected O, but got Unknown
		//IL_09e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a18: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a22: Expected O, but got Unknown
		//IL_0a2d: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)_runebornSkin != (Object)null) && !((Object)(object)GUI.skin == (Object)null))
		{
			_runebornSkin = Object.Instantiate<GUISkin>(GUI.skin);
			((Object)_runebornSkin).name = "RustyHeathensValheimSkin";
			Color fillColor = default(Color);
			((Color)(ref fillColor))..ctor(0.105f, 0.065f, 0.035f, 0.97f);
			Color fillColor2 = default(Color);
			((Color)(ref fillColor2))..ctor(0.175f, 0.105f, 0.052f, 0.97f);
			Color fillColor3 = default(Color);
			((Color)(ref fillColor3))..ctor(0.235f, 0.145f, 0.07f, 1f);
			Color fillColor4 = default(Color);
			((Color)(ref fillColor4))..ctor(0.315f, 0.205f, 0.105f, 1f);
			Color fillColor5 = default(Color);
			((Color)(ref fillColor5))..ctor(0.125f, 0.075f, 0.035f, 1f);
			Color borderColor = default(Color);
			((Color)(ref borderColor))..ctor(0.34f, 0.29f, 0.22f, 1f);
			Color borderColor2 = default(Color);
			((Color)(ref borderColor2))..ctor(0.63f, 0.43f, 0.19f, 1f);
			Color textColor = default(Color);
			((Color)(ref textColor))..ctor(0.89f, 0.84f, 0.72f, 1f);
			Color textColor2 = default(Color);
			((Color)(ref textColor2))..ctor(0.68f, 0.62f, 0.53f, 1f);
			Color textColor3 = default(Color);
			((Color)(ref textColor3))..ctor(0.92f, 0.72f, 0.38f, 1f);
			Color textColor4 = default(Color);
			((Color)(ref textColor4))..ctor(0.58f, 0.8f, 0.48f, 1f);
			Color textColor5 = default(Color);
			((Color)(ref textColor5))..ctor(0.92f, 0.48f, 0.32f, 1f);
			Texture2D background = CreateFramedTexture(fillColor, borderColor2);
			Texture2D background2 = CreateFramedTexture(fillColor2, borderColor);
			Texture2D background3 = CreateFramedTexture(fillColor3, borderColor);
			Texture2D background4 = CreateFramedTexture(fillColor4, borderColor2);
			Texture2D background5 = CreateFramedTexture(fillColor5, borderColor2);
			Texture2D background6 = CreateFramedTexture(new Color(0.16f, 0.28f, 0.12f, 1f), new Color(0.53f, 0.7f, 0.31f, 1f));
			Texture2D background7 = CreateFramedTexture(new Color(0.13f, 0.13f, 0.13f, 1f), borderColor);
			Texture2D background8 = CreateFramedTexture(new Color(0.26f, 0.09f, 0.07f, 1f), new Color(0.62f, 0.22f, 0.16f, 1f));
			Texture2D background9 = CreateFramedTexture(new Color(0.22f, 0.13f, 0.055f, 1f), borderColor2);
			Texture2D background10 = CreateFramedTexture(new Color(0.07f, 0.045f, 0.025f, 1f), borderColor);
			Texture2D background11 = CreateFramedTexture(new Color(0.31f, 0.2f, 0.1f, 1f), borderColor2);
			GUIStyle window = _runebornSkin.window;
			window.normal.background = background;
			window.hover.background = background;
			window.active.background = background;
			window.focused.background = background;
			window.onNormal.background = background;
			window.onHover.background = background;
			window.onActive.background = background;
			window.onFocused.background = background;
			window.normal.textColor = textColor3;
			window.hover.textColor = textColor3;
			window.active.textColor = textColor3;
			window.focused.textColor = textColor3;
			window.onNormal.textColor = textColor3;
			window.onHover.textColor = textColor3;
			window.onActive.textColor = textColor3;
			window.onFocused.textColor = textColor3;
			window.fontSize = 16;
			window.fontStyle = (FontStyle)1;
			window.alignment = (TextAnchor)1;
			window.padding = new RectOffset(14, 14, 34, 14);
			window.border = new RectOffset(1, 1, 1, 1);
			GUIStyle box = _runebornSkin.box;
			box.normal.background = background2;
			box.hover.background = background2;
			box.active.background = background2;
			box.focused.background = background2;
			box.onNormal.background = background2;
			box.onHover.background = background2;
			box.onActive.background = background2;
			box.onFocused.background = background2;
			box.normal.textColor = textColor;
			box.hover.textColor = textColor;
			box.active.textColor = textColor;
			box.focused.textColor = textColor;
			box.padding = new RectOffset(10, 10, 10, 10);
			box.border = new RectOffset(1, 1, 1, 1);
			GUIStyle label = _runebornSkin.label;
			label.normal.textColor = textColor;
			label.fontSize = 13;
			label.wordWrap = true;
			label.padding = new RectOffset(2, 2, 2, 2);
			GUIStyle button = _runebornSkin.button;
			button.normal.background = background3;
			button.hover.background = background4;
			button.active.background = background5;
			button.focused.background = background3;
			button.normal.textColor = textColor;
			button.hover.textColor = textColor3;
			button.active.textColor = textColor3;
			button.focused.textColor = textColor;
			button.fontSize = 13;
			button.alignment = (TextAnchor)4;
			button.padding = new RectOffset(8, 8, 5, 5);
			button.margin = new RectOffset(2, 2, 2, 2);
			button.fixedHeight = 28f;
			button.border = new RectOffset(1, 1, 1, 1);
			GUIStyle toggle = _runebornSkin.toggle;
			toggle.normal.textColor = textColor;
			toggle.hover.textColor = textColor3;
			toggle.active.textColor = textColor3;
			toggle.fontSize = 13;
			toggle.padding = new RectOffset(toggle.padding.left, toggle.padding.right, 4, 4);
			GUIStyle scrollView = _runebornSkin.scrollView;
			scrollView.normal.background = background2;
			scrollView.padding = new RectOffset(8, 8, 8, 8);
			scrollView.border = new RectOffset(1, 1, 1, 1);
			_runebornSkin.verticalScrollbar.normal.background = background10;
			_runebornSkin.verticalScrollbar.fixedWidth = 14f;
			_runebornSkin.verticalScrollbarThumb.normal.background = background11;
			_runebornSkin.verticalScrollbarThumb.hover.background = background4;
			_runebornSkin.verticalScrollbarThumb.active.background = background5;
			_runebornSkin.verticalScrollbarThumb.fixedWidth = 12f;
			_sectionHeaderStyle = new GUIStyle(label);
			_sectionHeaderStyle.normal.background = background9;
			_sectionHeaderStyle.normal.textColor = textColor3;
			_sectionHeaderStyle.fontSize = 15;
			_sectionHeaderStyle.fontStyle = (FontStyle)1;
			_sectionHeaderStyle.alignment = (TextAnchor)3;
			_sectionHeaderStyle.padding = new RectOffset(8, 8, 6, 6);
			_sectionHeaderStyle.margin = new RectOffset(0, 0, 8, 4);
			_sectionHeaderStyle.fixedHeight = 30f;
			_sectionHeaderStyle.border = new RectOffset(1, 1, 1, 1);
			_subHeaderStyle = new GUIStyle(label);
			_subHeaderStyle.normal.textColor = textColor3;
			_subHeaderStyle.fontSize = 14;
			_subHeaderStyle.fontStyle = (FontStyle)1;
			_subHeaderStyle.margin = new RectOffset(2, 2, 7, 2);
			_mutedLabelStyle = new GUIStyle(label);
			_mutedLabelStyle.normal.textColor = textColor2;
			_mutedLabelStyle.fontSize = 12;
			_goodLabelStyle = new GUIStyle(label);
			_goodLabelStyle.normal.textColor = textColor4;
			_goodLabelStyle.fontStyle = (FontStyle)1;
			_warningLabelStyle = new GUIStyle(label);
			_warningLabelStyle.normal.textColor = textColor5;
			_warningLabelStyle.fontStyle = (FontStyle)1;
			_accentLabelStyle = new GUIStyle(label);
			_accentLabelStyle.normal.textColor = textColor3;
			_accentLabelStyle.fontStyle = (FontStyle)1;
			_selectedButtonStyle = new GUIStyle(button);
			_selectedButtonStyle.normal.background = background6;
			_selectedButtonStyle.hover.background = background6;
			_selectedButtonStyle.normal.textColor = textColor;
			_selectedButtonStyle.hover.textColor = textColor3;
			_selectedButtonStyle.active.textColor = textColor3;
			_lockedButtonStyle = new GUIStyle(button);
			_lockedButtonStyle.normal.background = background7;
			_lockedButtonStyle.hover.background = background7;
			_lockedButtonStyle.normal.textColor = textColor;
			_lockedButtonStyle.hover.textColor = textColor3;
			_lockedButtonStyle.active.textColor = textColor3;
			_disabledButtonStyle = new GUIStyle(button);
			_disabledButtonStyle.normal.background = background8;
			_disabledButtonStyle.hover.background = background8;
			_disabledButtonStyle.normal.textColor = textColor5;
			_disabledButtonStyle.hover.textColor = textColor;
			_closeButtonStyle = new GUIStyle(button);
			_closeButtonStyle.fixedWidth = 26f;
			_closeButtonStyle.fixedHeight = 22f;
			_closeButtonStyle.fontSize = 12;
			_closeButtonStyle.fontStyle = (FontStyle)1;
			_closeButtonStyle.padding = new RectOffset(0, 0, 0, 0);
			_hudTitleStyle = new GUIStyle(label);
			_hudTitleStyle.normal.textColor = textColor3;
			_hudTitleStyle.fontSize = 13;
			_hudTitleStyle.fontStyle = (FontStyle)1;
			_hudTitleStyle.alignment = (TextAnchor)4;
			_hudLabelStyle = new GUIStyle(label);
			_hudLabelStyle.normal.textColor = textColor;
			_hudLabelStyle.fontSize = 13;
			_hudLabelStyle.richText = true;
			_hudLabelStyle.alignment = (TextAnchor)3;
		}
	}

	private Texture2D CreateFramedTexture(Color fillColor, Color borderColor)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Expected O, but got Unknown
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		Texture2D val = new Texture2D(3, 3, (TextureFormat)4, false);
		((Object)val).name = "RustyHeathensGuiTexture";
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)0;
		for (int i = 0; i < 3; i++)
		{
			for (int j = 0; j < 3; j++)
			{
				bool flag = j == 0 || j == 2 || i == 0 || i == 2;
				val.SetPixel(j, i, flag ? borderColor : fillColor);
			}
		}
		val.Apply();
		_guiTextures.Add(val);
		return val;
	}

	private void DrawSectionHeader(string title)
	{
		GUILayout.Label(title, _sectionHeaderStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>());
	}

	private void DrawSubHeader(string title)
	{
		GUILayout.Label(title, _subHeaderStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>());
	}

	private void DrawMutedLabel(string text)
	{
		GUILayout.Label(text, _mutedLabelStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>());
	}

	private bool DrawRunebornButton(string text)
	{
		GUIStyle val = GUI.skin.button;
		if (text.StartsWith("Selected:") || text.StartsWith("Enabled:"))
		{
			val = _selectedButtonStyle ?? GUI.skin.button;
		}
		else if (text.StartsWith("Locked:"))
		{
			val = _lockedButtonStyle ?? GUI.skin.button;
		}
		else if (text.StartsWith("Disabled:"))
		{
			val = _disabledButtonStyle ?? GUI.skin.button;
		}
		return GUILayout.Button(text, val, Array.Empty<GUILayoutOption>());
	}

	private void DrawSlotLimitButton(int slotCount)
	{
		bool num = RunebornServerComfort.GetMaxSelectedBuffs() == slotCount;
		string text = ((slotCount == 1) ? "1 Slot" : (slotCount + " Slots"));
		GUIStyle val = (num ? (_selectedButtonStyle ?? GUI.skin.button) : GUI.skin.button);
		if (GUILayout.Button(text, val, Array.Empty<GUILayoutOption>()))
		{
			RunebornServerComfort.SetMaxSelectedBuffs(slotCount);
		}
	}

	private void DrawServerComfortMenuContent()
	{
		DrawSectionHeader("PLAYER MENU");
		DrawMutedLabel("Rusty Heathens server information and personal settings");
		DrawMenuTabs(ref _playerMenuTab, "BUFFS", "SERVER", "HELP");
		switch (_playerMenuTab)
		{
		case 1:
			DrawPlayerServerTab();
			break;
		case 2:
			DrawPlayerHelpTab();
			break;
		default:
			DrawPlayerBuffsTab();
			break;
		}
	}

	private void DrawMenuTabs(ref int selectedTab, params string[] tabLabels)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		for (int i = 0; i < tabLabels.Length; i++)
		{
			GUIStyle val = ((i == selectedTab) ? (_selectedButtonStyle ?? GUI.skin.button) : GUI.skin.button);
			if (GUILayout.Button(tabLabels[i], val, Array.Empty<GUILayoutOption>()))
			{
				selectedTab = i;
				_scrollPosition = Vector2.zero;
				_adminScrollPosition = Vector2.zero;
			}
		}
		GUILayout.EndHorizontal();
		GUILayout.Space(6f);
	}

	private void DrawPlayerBuffsTab()
	{
		DrawSectionHeader("CHOOSE YOUR BUFFS");
		int selectedBuffCount = RunebornServerComfort.GetSelectedBuffCount();
		int maxSelectedBuffs = RunebornServerComfort.GetMaxSelectedBuffs();
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUIStyle val = ((selectedBuffCount > maxSelectedBuffs) ? (_warningLabelStyle ?? GUI.skin.label) : ((selectedBuffCount == maxSelectedBuffs) ? (_accentLabelStyle ?? GUI.skin.label) : (_goodLabelStyle ?? GUI.skin.label)));
		GUILayout.Label("Selected " + selectedBuffCount + " of " + maxSelectedBuffs, val, Array.Empty<GUILayoutOption>());
		GUILayout.FlexibleSpace();
		GUILayout.Label("Rested status controls activation", _mutedLabelStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>());
		GUILayout.EndHorizontal();
		DrawPlayerBuffChoice("rusty", "Rusty Buff");
		DrawPlayerBuffChoice("seppy", "Seppy Buff");
		DrawPlayerBuffChoice("xpert", "Xpert Buff");
		DrawPlayerBuffChoice("chaos", "Chaos Bringer Buff");
		DrawPlayerBuffChoice("witchy", "Witchy Buff");
		DrawSectionHeader("SELECTED BUFF DETAILS");
		DrawSelectedBuffDetails();
		DrawSectionHeader("UTILITY EFFECTS");
		DrawUtilityStatusCards();
	}

	private void DrawPlayerBuffChoice(string buffId, string displayName)
	{
		if (RunebornServerComfort.IsBuffEnabled(buffId))
		{
			string buffButtonText = RunebornServerComfort.GetBuffButtonText(buffId, displayName);
			if (DrawRunebornButton(buffButtonText))
			{
				ShowLocalCenterMessage(RunebornServerComfort.ToggleBuffSelection(buffId, displayName));
			}
		}
	}

	private bool IsBuffChosenForGui(string buffId, string displayName)
	{
		return RunebornServerComfort.GetBuffButtonText(buffId, displayName).StartsWith("Selected:", StringComparison.Ordinal);
	}

	private void DrawSelectedBuffDetails()
	{
		bool flag = false;
		if (IsBuffChosenForGui("rusty", "Rusty Buff"))
		{
			flag = true;
			DrawBuffStatusCard("Rusty Buff", RunebornServerComfort.IsRustyRestedActiveForLocalPlayer(), "Requires Rested", "10% less stamina used");
		}
		if (IsBuffChosenForGui("seppy", "Seppy Buff"))
		{
			flag = true;
			DrawBuffStatusCard("Seppy Buff", RunebornServerComfort.IsSeppyBuffActiveForLocalPlayer(), "Requires Rested", "10% less incoming damage", "15% less stamina used while blocking");
		}
		if (IsBuffChosenForGui("xpert", "Xpert Buff"))
		{
			flag = true;
			DrawBuffStatusCard("Xpert Buff", RunebornServerComfort.IsXpertBuffActiveForLocalPlayer(), "Requires Rested and an axe or melee weapon", "10% more melee damage", "10% less weapon stamina used");
		}
		if (IsBuffChosenForGui("chaos", "Chaos Bringer Buff"))
		{
			flag = true;
			DrawBuffStatusCard("Chaos Bringer", RunebornServerComfort.IsChaosBringerBuffActiveForLocalPlayer(), "Requires Rested", "10% faster movement", "20% faster sneak", "12% stronger jump", "15% less dodge and swim stamina");
		}
		if (IsBuffChosenForGui("witchy", "Witchy Buff"))
		{
			flag = true;
			DrawBuffStatusCard("Witchy Buff", RunebornServerComfort.IsWitchyBuffActiveForLocalPlayer(), "Requires Rested", "10% less staff and magic stamina");
		}
		if (!flag)
		{
			GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
			DrawMutedLabel("Choose a buff above to see its active effects.");
			GUILayout.EndVertical();
		}
	}

	private void DrawBuffStatusCard(string title, bool active, string inactiveRequirement, params string[] effectLines)
	{
		GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		GUILayout.Label(title, _subHeaderStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>());
		GUILayout.FlexibleSpace();
		GUILayout.Label(active ? "ACTIVE" : "INACTIVE", active ? (_goodLabelStyle ?? GUI.skin.label) : (_warningLabelStyle ?? GUI.skin.label), Array.Empty<GUILayoutOption>());
		GUILayout.EndHorizontal();
		if (!active)
		{
			DrawMutedLabel(inactiveRequirement);
		}
		foreach (string text in effectLines)
		{
			GUILayout.Label("• " + text, Array.Empty<GUILayoutOption>());
		}
		GUILayout.EndVertical();
	}

	private void DrawUtilityStatusCards()
	{
		bool flag = RunebornServerComfort.IsBuildComfortActiveForLocalPlayer();
		GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		DrawSubHeader("Build Mode Comfort");
		GUILayout.FlexibleSpace();
		GUILayout.Label(flag ? "ACTIVE" : "READY", flag ? (_goodLabelStyle ?? GUI.skin.label) : (_mutedLabelStyle ?? GUI.skin.label), Array.Empty<GUILayoutOption>());
		GUILayout.EndHorizontal();
		DrawMutedLabel(flag ? "50% less stamina used while building" : "Equip a Hammer, Hoe, or Cultivator");
		GUILayout.EndVertical();
		float bodyRecoverySecondsLeft = RunebornServerComfort.GetBodyRecoverySecondsLeft();
		GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		DrawSubHeader("Body Recovery");
		GUILayout.FlexibleSpace();
		GUILayout.Label((bodyRecoverySecondsLeft > 0f) ? "ACTIVE" : "INACTIVE", (bodyRecoverySecondsLeft > 0f) ? (_goodLabelStyle ?? GUI.skin.label) : (_mutedLabelStyle ?? GUI.skin.label), Array.Empty<GUILayoutOption>());
		GUILayout.EndHorizontal();
		if (bodyRecoverySecondsLeft > 0f)
		{
			DrawMutedLabel(Mathf.CeilToInt(bodyRecoverySecondsLeft / 60f) + " minutes remaining");
			GUILayout.Label("• +150 carry weight\n• 35% less stamina used", Array.Empty<GUILayoutOption>());
		}
		else
		{
			DrawMutedLabel("Activates for 10 minutes after death");
		}
		GUILayout.EndVertical();
	}

	private void DrawPlayerServerTab()
	{
		DrawSectionHeader("SERVER STATUS");
		DrawServerStatusCard("Welcome Message", enabled: true, "Shown once after loading into the world.");
		DrawServerStatusCard("Server Reminder", RunebornServerReminder.ServerReminderEnabled, "Shown once after the welcome message.");
		DrawServerStatusCard("Raid Warnings", RunebornRaidWarnings.RaidWarningsEnabled, "Warns when raids start, repeat, and clear.");
		DrawServerStatusCard("Boss Kill Messages", enabled: true, "Shows a Rusty Heathens victory message.");
		DrawSectionHeader("DEATH COUNTER");
		int currentDeathCount = PlayerPrefs.GetInt("RustyHeathensRuneborn.DeathCount", 0);
		GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
		GUILayout.Label("Deaths: " + currentDeathCount, _subHeaderStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>());
		DrawMutedLabel("Next message: " + RunebornServerComfort.PreviewNextFunnyDeathMessage(currentDeathCount));
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		if (DrawRunebornButton("Show Count"))
		{
			ShowLocalCenterMessage("Rusty Heathens Death Count: " + currentDeathCount);
		}
		if (DrawRunebornButton("Reset Count"))
		{
			PlayerPrefs.SetInt("RustyHeathensRuneborn.DeathCount", 0);
			PlayerPrefs.Save();
			ShowLocalCenterMessage("Rusty Heathens Death Count reset");
		}
		GUILayout.EndHorizontal();
		GUILayout.EndVertical();
	}

	private void DrawServerStatusCard(string title, bool enabled, string description)
	{
		GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		DrawSubHeader(title);
		GUILayout.FlexibleSpace();
		GUILayout.Label(enabled ? "ON" : "OFF", enabled ? (_goodLabelStyle ?? GUI.skin.label) : (_warningLabelStyle ?? GUI.skin.label), Array.Empty<GUILayoutOption>());
		GUILayout.EndHorizontal();
		DrawMutedLabel(description);
		GUILayout.EndVertical();
	}

	private void DrawPlayerHelpTab()
	{
		DrawSectionHeader("SERVER RULES & HELP");
		DrawMutedLabel("Choose a topic to display it in the center of the screen.");
		if (DrawRunebornButton("Basic Server Rules"))
		{
			ShowLocalCenterMessage("RUSTY HEATHENS RULES\nRespect the crew.\nNo stealing.\nNo boss fights without the group.\nHelp with body recovery when you can.\nCheck Discord for full rules.");
		}
		if (DrawRunebornButton("Boss Fight Rules"))
		{
			ShowLocalCenterMessage("BOSS FIGHT RULES\nDo not summon bosses alone.\nWait for Rusty and the group.\nRepair gear, bring food, and be ready.\nIf you die, call for recovery.");
		}
		if (DrawRunebornButton("Body Recovery Rules"))
		{
			ShowLocalCenterMessage("BODY RECOVERY RULES\nDo not run in alone if the area is hot.\nCall out where your body is.\nStay grouped and protect each other.\nRecovery before revenge.");
		}
		if (DrawRunebornButton("Discord Reminder"))
		{
			ShowLocalCenterMessage("DISCORD REMINDER\nUse Discord for rules, event plans, updates, and stream info.\nMessage RustyLaser if you need help.");
		}
		if (DrawRunebornButton("Server Etiquette"))
		{
			ShowLocalCenterMessage("SERVER ETIQUETTE\nAsk before taking shared items.\nLabel storage when possible.\nDo not spoil new areas or bosses.\nBuild smart, clean up, and help the crew.");
		}
		DrawSectionHeader("SERVER EVENTS");
		DrawMutedLabel(RunebornAdminTools.IsLocalAdmin() ? "Event broadcasts are controlled from F7." : "Server-event broadcasts appear automatically.");
	}

	private void ShowBuffAvailabilityMessage(string message)
	{
		if ((Object)(object)Player.m_localPlayer != (Object)null)
		{
			((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null);
		}
	}

	private void DrawAdminMenuContent()
	{
		DrawSectionHeader("ADMIN MENU");
		DrawMutedLabel("Server-owner controls - F7");
		DrawMenuTabs(ref _adminMenuTab, "SETTINGS", "EVENTS", "SYSTEM");
		switch (_adminMenuTab)
		{
		case 1:
			DrawAdminEventsTab();
			break;
		case 2:
			DrawAdminSystemTab();
			break;
		default:
			DrawAdminSettingsTab();
			break;
		}
	}

	private void DrawAdminSettingsTab()
	{
		DrawSectionHeader("SERVER SETTINGS");
		DrawSubHeader("Maximum Buff Slots");
		DrawMutedLabel("Choose how many character buffs each player may equip.");
		GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
		DrawSlotLimitButton(1);
		DrawSlotLimitButton(2);
		DrawSlotLimitButton(3);
		GUILayout.EndHorizontal();
		GUILayout.Label("Admin authority active", _goodLabelStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>());
		DrawSectionHeader("BUFF AVAILABILITY");
		DrawAdminBuffAvailabilityButton("rusty", "Rusty Buff");
		DrawAdminBuffAvailabilityButton("seppy", "Seppy Buff");
		DrawAdminBuffAvailabilityButton("xpert", "Xpert Buff");
		DrawAdminBuffAvailabilityButton("chaos", "Chaos Bringer Buff");
		DrawAdminBuffAvailabilityButton("witchy", "Witchy Buff");
		DrawMutedLabel("Enabled: " + RunebornServerComfort.GetEnabledBuffSummary());
		GUILayout.Label("Multiplayer availability sync active", _goodLabelStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>());
		DrawSectionHeader("ADMIN TOGGLES");
		DrawAdminSettingToggle("Server Reminder", ServerReminderEnabledEntry, "Server Reminder");
		DrawAdminSettingToggle("Raid Warnings", RaidWarningsEnabledEntry, "Raid Warnings");
	}

	private void DrawAdminSettingToggle(string displayName, ConfigEntry<bool> configEntry, string messageName)
	{
		bool value = configEntry.Value;
		string text = (value ? "Enabled: " : "Disabled: ") + displayName + " - click to " + (value ? "disable" : "enable");
		if (DrawRunebornButton(text))
		{
			configEntry.Value = !value;
			ApplyAdminSettingsToRuntime();
			((BaseUnityPlugin)this).Config.Save();
			ShowLocalCenterMessage(messageName + " " + (configEntry.Value ? "Enabled" : "Disabled"));
		}
	}

	private void DrawAdminBuffAvailabilityButton(string buffId, string displayName)
	{
		string buffEnabledButtonText = RunebornServerComfort.GetBuffEnabledButtonText(buffId, displayName);
		if (DrawRunebornButton(buffEnabledButtonText))
		{
			ShowBuffAvailabilityMessage(RunebornServerComfort.ToggleBuffEnabledByAdmin(buffId, displayName));
		}
	}

	private void DrawAdminEventsTab()
	{
		DrawSectionHeader("SERVER EVENTS");
		DrawMutedLabel("Broadcast a large center-screen message to every player.");
		if (DrawRunebornButton("Boss Fight Starting Soon"))
		{
			RunebornAdminEventMessages.SendAdminBroadcast("BOSS FIGHT STARTING SOON", "Return to base, repair your gear, grab food, and wait for Rusty.");
		}
		if (DrawRunebornButton("Return To Base"))
		{
			RunebornAdminEventMessages.SendAdminBroadcast("RETURN TO BASE", "Everyone head back to base. Regroup before the chaos gets worse.");
		}
		if (DrawRunebornButton("Body Recovery Run"))
		{
			RunebornAdminEventMessages.SendAdminBroadcast("BODY RECOVERY RUN", "A Heathen is down. Gear up, stay together, and help recover the body.");
		}
		if (DrawRunebornButton("Discord Reminder"))
		{
			RunebornAdminEventMessages.SendAdminBroadcast("DISCORD REMINDER", "Check Discord for server rules, event plans, and stream updates.");
		}
		if (DrawRunebornButton("Stream Starting Soon"))
		{
			RunebornAdminEventMessages.SendAdminBroadcast("STREAM STARTING SOON", "Get ready, Heathens. The stream is about to begin.");
		}
	}

	private void DrawAdminSystemTab()
	{
		DrawSectionHeader("SYSTEM STATUS");
		GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
		GUILayout.Label("Runeborn v0.4.2", _subHeaderStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>());
		GUILayout.Label("Buff-slot synchronization: " + (RunebornBuffSlotSyncFoundation.WasLastSenderTrusted() ? "TRUSTED" : "ADMIN AUTHORITY"), _goodLabelStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>());
		GUILayout.Label("Availability synchronization: " + (RunebornBuffAvailabilitySync.WasLastSenderTrusted() ? "TRUSTED" : "ADMIN AUTHORITY"), _goodLabelStyle ?? GUI.skin.label, Array.Empty<GUILayoutOption>());
		DrawMutedLabel("Late-join request and response synchronization is active.");
		GUILayout.EndVertical();
		DrawSectionHeader("BUFF-SLOT DIAGNOSTICS");
		GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
		DrawMutedLabel("Current slot limit: " + RunebornServerComfort.GetMaxSelectedBuffs());
		DrawMutedLabel("Last received value: " + RunebornBuffSlotSyncFoundation.GetLastReceivedMaxBuffSlots());
		DrawMutedLabel("Last RPC sender: " + RunebornBuffSlotSyncFoundation.GetLastRpcSender());
		DrawMutedLabel("Server peer ID: " + RunebornBuffSlotSyncFoundation.GetLastServerPeerId());
		DrawMutedLabel("Local peer ID: " + RunebornBuffSlotSyncFoundation.GetLastLocalPeerId());
		DrawMutedLabel("Last request sender: " + RunebornBuffSlotSyncFoundation.GetLastRequestSender());
		DrawMutedLabel("Live ID equality: " + (RunebornBuffSlotSyncFoundation.DoLastRpcIdsMatch() ? "YES" : "NO"));
		DrawMutedLabel("Sender hex: " + RunebornBuffSlotSyncFoundation.GetLastRpcSenderHex());
		DrawMutedLabel("Server hex: " + RunebornBuffSlotSyncFoundation.GetLastServerPeerIdHex());
		GUILayout.EndVertical();
		DrawSectionHeader("AVAILABILITY DIAGNOSTICS");
		GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
		DrawMutedLabel("Enabled mask: " + RunebornServerComfort.GetEnabledBuffMask());
		DrawMutedLabel("Last received mask: " + RunebornBuffAvailabilitySync.GetLastReceivedMask());
		DrawMutedLabel("Last RPC sender: " + RunebornBuffAvailabilitySync.GetLastRpcSender());
		DrawMutedLabel("Last request sender: " + RunebornBuffAvailabilitySync.GetLastRequestSender());
		GUILayout.EndVertical();
		DrawSectionHeader("ADMIN ID");
		GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
		DrawMutedLabel(RunebornAdminTools.GetLocalAdminDebugText());
		GUILayout.EndVertical();
	}
}
public sealed class RunebornRustyStatusEffect : StatusEffect
{
	public override string GetTooltipString()
	{
		return "10% less stamina used while Rested.";
	}
}
public sealed class RunebornSeppyStatusEffect : StatusEffect
{
	public override string GetTooltipString()
	{
		return "10% less incoming damage.\n15% less stamina used while blocking.";
	}
}
public sealed class RunebornXpertStatusEffect : StatusEffect
{
	public override string GetTooltipString()
	{
		return "10% more melee damage.\n10% less weapon stamina used while Rested with a melee weapon.";
	}
}
public sealed class RunebornChaosStatusEffect : StatusEffect
{
	public override string GetTooltipString()
	{
		return "10% faster movement.\n20% faster sneak.\n12% stronger jump.\n15% less dodge and swim stamina.";
	}
}
public sealed class RunebornWitchyStatusEffect : StatusEffect
{
	public override string GetTooltipString()
	{
		return "10% less staff and magic stamina while Rested.";
	}
}
public static class RunebornBuffStatusEffects
{
	private const string RustyEffectName = "SE_RustyHeathens_RustyBuff";

	private const string SeppyEffectName = "SE_RustyHeathens_SeppyBuff";

	private const string XpertEffectName = "SE_RustyHeathens_XpertBuff";

	private const string ChaosEffectName = "SE_RustyHeathens_ChaosBringerBuff";

	private const string WitchyEffectName = "SE_RustyHeathens_WitchyBuff";

	private static readonly int RustyEffectHash = StringExtensionMethods.GetStableHashCode("SE_RustyHeathens_RustyBuff");

	private static readonly int SeppyEffectHash = StringExtensionMethods.GetStableHashCode("SE_RustyHeathens_SeppyBuff");

	private static readonly int XpertEffectHash = StringExtensionMethods.GetStableHashCode("SE_RustyHeathens_XpertBuff");

	private static readonly int ChaosEffectHash = StringExtensionMethods.GetStableHashCode("SE_RustyHeathens_ChaosBringerBuff");

	private static readonly int WitchyEffectHash = StringExtensionMethods.GetStableHashCode("SE_RustyHeathens_WitchyBuff");

	private static bool _registered;

	private static CustomStatusEffect _rustyStatusEffect;

	private static CustomStatusEffect _seppyStatusEffect;

	private static CustomStatusEffect _xpertStatusEffect;

	private static CustomStatusEffect _chaosStatusEffect;

	private static CustomStatusEffect _witchyStatusEffect;

	public static void Register()
	{
		if (!_registered)
		{
			Sprite val = LoadIconSprite("RustyBuffIcon_128.png");
			Sprite val2 = LoadIconSprite("SeppyBuffIcon_128.png");
			Sprite val3 = LoadIconSprite("XpertBuffIcon_128.png");
			Sprite val4 = LoadIconSprite("ChaosBringerBuffIcon_128.png");
			Sprite val5 = LoadIconSprite("WitchyBuffIcon_128.png");
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null) && !((Object)(object)val3 == (Object)null) && !((Object)(object)val4 == (Object)null) && !((Object)(object)val5 == (Object)null))
			{
				_rustyStatusEffect = RegisterStatusEffect<RunebornRustyStatusEffect>("SE_RustyHeathens_RustyBuff", "Rusty Buff", val, "10% less stamina used while Rested.");
				_seppyStatusEffect = RegisterStatusEffect<RunebornSeppyStatusEffect>("SE_RustyHeathens_SeppyBuff", "Seppy Buff", val2, "10% less incoming damage and 15% less blocking stamina.");
				_xpertStatusEffect = RegisterStatusEffect<RunebornXpertStatusEffect>("SE_RustyHeathens_XpertBuff", "Xpert Buff", val3, "10% more melee damage and 10% less weapon stamina.");
				_chaosStatusEffect = RegisterStatusEffect<RunebornChaosStatusEffect>("SE_RustyHeathens_ChaosBringerBuff", "Chaos Bringer", val4, "Movement, sneak, jump, dodge, and swim bonuses.");
				_witchyStatusEffect = RegisterStatusEffect<RunebornWitchyStatusEffect>("SE_RustyHeathens_WitchyBuff", "Witchy Buff", val5, "10% less staff and magic stamina while Rested.");
				_registered = _rustyStatusEffect != null && _seppyStatusEffect != null && _xpertStatusEffect != null && _chaosStatusEffect != null && _witchyStatusEffect != null;
			}
		}
	}

	public static void UpdateLocalPlayerEffects()
	{
		if (!_registered)
		{
			Register();
		}
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null))
		{
			SEMan sEMan = ((Character)localPlayer).GetSEMan();
			if (sEMan != null)
			{
				SyncStatusEffect(sEMan, RustyEffectHash, RunebornServerComfort.IsRustyRestedActiveForLocalPlayer());
				SyncStatusEffect(sEMan, SeppyEffectHash, RunebornServerComfort.IsSeppyBuffActiveForLocalPlayer());
				SyncStatusEffect(sEMan, XpertEffectHash, RunebornServerComfort.IsXpertBuffActiveForLocalPlayer());
				SyncStatusEffect(sEMan, ChaosEffectHash, RunebornServerComfort.IsChaosBringerBuffActiveForLocalPlayer());
				SyncStatusEffect(sEMan, WitchyEffectHash, RunebornServerComfort.IsWitchyBuffActiveForLocalPlayer());
			}
		}
	}

	private static CustomStatusEffect RegisterStatusEffect<T>(string effectName, string displayName, Sprite icon, string fallbackTooltip) where T : StatusEffect
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Expected O, but got Unknown
		try
		{
			T val = ScriptableObject.CreateInstance<T>();
			((Object)(object)val).name = effectName;
			((StatusEffect)val).m_name = displayName;
			((StatusEffect)val).m_tooltip = fallbackTooltip;
			((StatusEffect)val).m_icon = icon;
			((StatusEffect)val).m_ttl = 0f;
			CustomStatusEffect val2 = new CustomStatusEffect((StatusEffect)(object)val, false);
			ItemManager.Instance.AddStatusEffect(val2);
			return val2;
		}
		catch
		{
			return null;
		}
	}

	private static void SyncStatusEffect(SEMan statusManager, int effectHash, bool shouldBeActive)
	{
		bool flag = statusManager.HaveStatusEffect(effectHash);
		if (shouldBeActive && !flag)
		{
			statusManager.AddStatusEffect(effectHash, true, 0, 0f);
		}
		else if (!shouldBeActive && flag)
		{
			statusManager.RemoveStatusEffect(effectHash, false);
		}
	}

	private static Sprite LoadIconSprite(string fileName)
	{
		try
		{
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			if (string.IsNullOrEmpty(directoryName))
			{
				return null;
			}
			string text = Path.Combine(directoryName, "Assets", fileName);
			if (!File.Exists(text))
			{
				return null;
			}
			return AssetUtils.LoadSpriteFromFile(text);
		}
		catch
		{
			return null;
		}
	}
}
public static class RunebornBuffSlotSyncFoundation
{
	private const string RpcName = "RustyHeathensRuneborn.BuffSlotSyncFoundation";

	private const string RequestRpcName = "RustyHeathensRuneborn.BuffSlotSyncRequest";

	private static bool _registered;

	private static bool _lateJoinRequestSent;

	private static float _nextLateJoinRequestTime;

	private static long _requestedServerPeerId = long.MinValue;

	private static long _lastRequestSender;

	private static int _lastReceivedMaxBuffSlots;

	private static long _lastRpcSender;

	private static long _lastServerPeerId = long.MinValue;

	private static long _lastLocalPeerId = long.MinValue;

	private static bool _lastSenderTrusted;

	public static void EnsureRegistered()
	{
		if (_registered || ZRoutedRpc.instance == null)
		{
			return;
		}
		try
		{
			ZRoutedRpc.instance.Register<int>("RustyHeathensRuneborn.BuffSlotSyncFoundation", (Action<long, int>)RPC_BuffSlotSyncFoundation);
			ZRoutedRpc.instance.Register<int>("RustyHeathensRuneborn.BuffSlotSyncRequest", (Action<long, int>)RPC_BuffSlotSyncRequest);
			_registered = true;
		}
		catch
		{
			_registered = true;
		}
	}

	public static long GetLastRequestSender()
	{
		return _lastRequestSender;
	}

	public static void UpdateLateJoinRequest()
	{
		EnsureRegistered();
		if (!_registered || ZRoutedRpc.instance == null || RunebornAdminTools.IsLocalAdmin() || (Object)(object)Player.m_localPlayer == (Object)null)
		{
			return;
		}
		long num = TryGetRoutedRpcId("GetServerPeerID");
		if (num == long.MinValue)
		{
			return;
		}
		if (_requestedServerPeerId != num)
		{
			_requestedServerPeerId = num;
			_lateJoinRequestSent = false;
			_nextLateJoinRequestTime = 0f;
		}
		if (_lateJoinRequestSent || Time.unscaledTime < _nextLateJoinRequestTime)
		{
			return;
		}
		try
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(num, "RustyHeathensRuneborn.BuffSlotSyncRequest", new object[1] { 1 });
			_lateJoinRequestSent = true;
		}
		catch
		{
			_nextLateJoinRequestTime = Time.unscaledTime + 2f;
		}
	}

	public static int GetLastReceivedMaxBuffSlots()
	{
		return _lastReceivedMaxBuffSlots;
	}

	public static long GetLastRpcSender()
	{
		return _lastRpcSender;
	}

	public static long GetLastServerPeerId()
	{
		return _lastServerPeerId;
	}

	public static long GetLastLocalPeerId()
	{
		return _lastLocalPeerId;
	}

	public static bool WasLastSenderTrusted()
	{
		return _lastSenderTrusted;
	}

	public static bool DoLastRpcIdsMatch()
	{
		if (_lastServerPeerId != long.MinValue)
		{
			return _lastRpcSender == _lastServerPeerId;
		}
		return false;
	}

	public static string GetLastRpcSenderHex()
	{
		ulong lastRpcSender = (ulong)_lastRpcSender;
		return lastRpcSender.ToString("X16");
	}

	public static string GetLastServerPeerIdHex()
	{
		ulong lastServerPeerId = (ulong)_lastServerPeerId;
		return lastServerPeerId.ToString("X16");
	}

	private static long TryGetRoutedRpcId(string methodName)
	{
		if (ZRoutedRpc.instance == null)
		{
			return long.MinValue;
		}
		try
		{
			MethodInfo method = typeof(ZRoutedRpc).GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return long.MinValue;
			}
			object obj = method.Invoke(ZRoutedRpc.instance, null);
			if (obj == null)
			{
				return long.MinValue;
			}
			return Convert.ToInt64(obj);
		}
		catch
		{
			return long.MinValue;
		}
	}

	private static bool IsTrustedServerSender(long sender)
	{
		_lastServerPeerId = TryGetRoutedRpcId("GetServerPeerID");
		_lastLocalPeerId = TryGetRoutedRpcId("GetUID");
		if (_lastServerPeerId == long.MinValue)
		{
			return false;
		}
		return sender.ToString() == _lastServerPeerId.ToString();
	}

	public static void BroadcastMaxBuffSlots(int maxBuffs)
	{
		if (!RunebornAdminTools.IsLocalAdmin())
		{
			return;
		}
		EnsureRegistered();
		if (ZRoutedRpc.instance == null)
		{
			return;
		}
		int num = Mathf.Clamp(maxBuffs, 1, 3);
		try
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RustyHeathensRuneborn.BuffSlotSyncFoundation", new object[1] { num });
		}
		catch
		{
		}
	}

	private static void RPC_BuffSlotSyncRequest(long sender, int value)
	{
		_lastRequestSender = sender;
		if (!RunebornAdminTools.IsLocalAdmin() || ZRoutedRpc.instance == null)
		{
			return;
		}
		int num = Mathf.Clamp(RunebornServerComfort.GetMaxSelectedBuffs(), 1, 3);
		try
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "RustyHeathensRuneborn.BuffSlotSyncFoundation", new object[1] { num });
		}
		catch
		{
		}
	}

	private static void RPC_BuffSlotSyncFoundation(long sender, int value)
	{
		_lastRpcSender = sender;
		_lastSenderTrusted = IsTrustedServerSender(sender);
		if (_lastSenderTrusted)
		{
			_lastReceivedMaxBuffSlots = Mathf.Clamp(value, 1, 3);
			RunebornServerComfort.ApplySyncedMaxSelectedBuffs(_lastReceivedMaxBuffSlots);
		}
	}
}
public static class RunebornBuffAvailabilitySync
{
	private const string ValueRpcName = "RustyHeathensRuneborn.BuffAvailabilitySyncValue";

	private const string RequestRpcName = "RustyHeathensRuneborn.BuffAvailabilitySyncRequest";

	private const int AllBuffsMask = 31;

	private static bool _registered;

	private static bool _lateJoinRequestSent;

	private static float _nextLateJoinRequestTime;

	private static long _requestedServerPeerId = long.MinValue;

	private static int _lastReceivedMask = 31;

	private static long _lastRpcSender;

	private static long _lastServerPeerId = long.MinValue;

	private static long _lastRequestSender;

	private static bool _lastSenderTrusted;

	public static void EnsureRegistered()
	{
		if (_registered || ZRoutedRpc.instance == null)
		{
			return;
		}
		try
		{
			ZRoutedRpc.instance.Register<int>("RustyHeathensRuneborn.BuffAvailabilitySyncValue", (Action<long, int>)RPC_BuffAvailabilityValue);
			ZRoutedRpc.instance.Register<int>("RustyHeathensRuneborn.BuffAvailabilitySyncRequest", (Action<long, int>)RPC_BuffAvailabilityRequest);
			_registered = true;
		}
		catch
		{
			_registered = true;
		}
	}

	public static void UpdateLateJoinRequest()
	{
		EnsureRegistered();
		if (!_registered || ZRoutedRpc.instance == null || RunebornAdminTools.IsLocalAdmin() || (Object)(object)Player.m_localPlayer == (Object)null)
		{
			return;
		}
		long num = TryGetRoutedRpcId("GetServerPeerID");
		if (num == long.MinValue)
		{
			return;
		}
		if (_requestedServerPeerId != num)
		{
			_requestedServerPeerId = num;
			_lateJoinRequestSent = false;
			_nextLateJoinRequestTime = 0f;
		}
		if (_lateJoinRequestSent || Time.unscaledTime < _nextLateJoinRequestTime)
		{
			return;
		}
		try
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(num, "RustyHeathensRuneborn.BuffAvailabilitySyncRequest", new object[1] { 1 });
			_lateJoinRequestSent = true;
		}
		catch
		{
			_nextLateJoinRequestTime = Time.unscaledTime + 2f;
		}
	}

	public static void BroadcastEnabledBuffMask(int enabledMask)
	{
		if (!RunebornAdminTools.IsLocalAdmin())
		{
			return;
		}
		EnsureRegistered();
		if (ZRoutedRpc.instance == null)
		{
			return;
		}
		int num = enabledMask & 0x1F;
		try
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RustyHeathensRuneborn.BuffAvailabilitySyncValue", new object[1] { num });
		}
		catch
		{
		}
	}

	public static int GetLastReceivedMask()
	{
		return _lastReceivedMask;
	}

	public static long GetLastRpcSender()
	{
		return _lastRpcSender;
	}

	public static long GetLastRequestSender()
	{
		return _lastRequestSender;
	}

	public static bool WasLastSenderTrusted()
	{
		return _lastSenderTrusted;
	}

	private static void RPC_BuffAvailabilityRequest(long sender, int value)
	{
		_lastRequestSender = sender;
		if (!RunebornAdminTools.IsLocalAdmin() || ZRoutedRpc.instance == null)
		{
			return;
		}
		int num = RunebornServerComfort.GetEnabledBuffMask() & 0x1F;
		try
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(sender, "RustyHeathensRuneborn.BuffAvailabilitySyncValue", new object[1] { num });
		}
		catch
		{
		}
	}

	private static void RPC_BuffAvailabilityValue(long sender, int value)
	{
		_lastRpcSender = sender;
		_lastSenderTrusted = IsTrustedServerSender(sender);
		if (_lastSenderTrusted)
		{
			_lastReceivedMask = value & 0x1F;
			RunebornServerComfort.ApplySyncedEnabledBuffMask(_lastReceivedMask);
		}
	}

	private static bool IsTrustedServerSender(long sender)
	{
		_lastServerPeerId = TryGetRoutedRpcId("GetServerPeerID");
		if (_lastServerPeerId != long.MinValue)
		{
			return sender == _lastServerPeerId;
		}
		return false;
	}

	private static long TryGetRoutedRpcId(string methodName)
	{
		if (ZRoutedRpc.instance == null)
		{
			return long.MinValue;
		}
		try
		{
			MethodInfo method = typeof(ZRoutedRpc).GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return long.MinValue;
			}
			object obj = method.Invoke(ZRoutedRpc.instance, null);
			return (obj != null) ? Convert.ToInt64(obj) : long.MinValue;
		}
		catch
		{
			return long.MinValue;
		}
	}
}
public static class RunebornAdminEventMessages
{
	private const string RpcName = "RustyHeathensRuneborn.AdminEventMessage";

	private static bool _registered;

	public static void EnsureRegistered()
	{
		if (_registered || ZRoutedRpc.instance == null)
		{
			return;
		}
		try
		{
			ZRoutedRpc.instance.Register<string>("RustyHeathensRuneborn.AdminEventMessage", (Action<long, string>)RPC_AdminEventMessage);
			_registered = true;
		}
		catch
		{
			_registered = true;
		}
	}

	public static void SendAdminBroadcast(string title, string body)
	{
		if (!RunebornAdminTools.IsLocalAdmin())
		{
			ShowLocal("Admin event buttons are locked.");
			return;
		}
		EnsureRegistered();
		string text = "RUSTY HEATHENS EVENT\n" + title + "\n" + body;
		if (ZRoutedRpc.instance == null)
		{
			ShowLocal(text);
			return;
		}
		try
		{
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RustyHeathensRuneborn.AdminEventMessage", new object[1] { text });
		}
		catch
		{
			ShowLocal(text);
		}
	}

	private static void RPC_AdminEventMessage(long sender, string message)
	{
		ShowLocal(message);
	}

	private static void ShowLocal(string message)
	{
		if ((Object)(object)Player.m_localPlayer == (Object)null)
		{
			return;
		}
		try
		{
			((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null);
		}
		catch
		{
		}
	}
}
public static class RunebornAdminTools
{
	private const string RustySteamId = "76561198921017348";

	public static bool IsLocalAdmin()
	{
		try
		{
			return GetLocalAdminDebugText().Contains("76561198921017348");
		}
		catch
		{
			return false;
		}
	}

	public static string GetLocalAdminDebugText()
	{
		try
		{
			List<string> localSteamIdCandidates = GetLocalSteamIdCandidates();
			if (localSteamIdCandidates.Count == 0)
			{
				return "No SteamID detected";
			}
			return string.Join(", ", localSteamIdCandidates.ToArray());
		}
		catch
		{
			return "SteamID debug failed";
		}
	}

	private static List<string> GetLocalSteamIdCandidates()
	{
		List<string> list = new List<string>();
		try
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				AddCandidate(list, TryCallNoArgs(localPlayer, "GetPlayerID"));
				AddCandidate(list, TryCallNoArgs(localPlayer, "GetNetworkUserId"));
				AddCandidate(list, TryCallNoArgs(localPlayer, "GetSteamID"));
				AddCandidate(list, GetFieldValue(localPlayer, "m_playerID"));
				AddCandidate(list, GetFieldValue(localPlayer, "m_steamID"));
			}
			object zNetInstance = GetZNetInstance();
			if (zNetInstance != null)
			{
				AddCandidate(list, TryCallNoArgs(zNetInstance, "GetUID"));
				AddCandidate(list, TryCallNoArgs(zNetInstance, "GetSteamID"));
				AddCandidate(list, GetFieldValue(zNetInstance, "m_steamID"));
				AddCandidate(list, GetFieldValue(zNetInstance, "m_mySteamID"));
				AddCandidate(list, GetFieldValue(zNetInstance, "m_steamId"));
				AddCandidate(list, GetFieldValue(zNetInstance, "m_userID"));
			}
			AddSteamworksCandidate(list);
			AddKnownTypeCandidates(list);
		}
		catch
		{
		}
		return list;
	}

	private static void AddCandidate(List<string> candidates, object value)
	{
		if (value == null)
		{
			return;
		}
		AddCandidateString(candidates, value.ToString());
		Type type = value.GetType();
		FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (FieldInfo fieldInfo in fields)
		{
			string text = fieldInfo.Name.ToLowerInvariant();
			if (!text.Contains("id") && !text.Contains("steam"))
			{
				continue;
			}
			try
			{
				object value2 = fieldInfo.GetValue(value);
				if (value2 != null)
				{
					AddCandidateString(candidates, value2.ToString());
				}
			}
			catch
			{
			}
		}
		PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (PropertyInfo propertyInfo in properties)
		{
			string text2 = propertyInfo.Name.ToLowerInvariant();
			if ((!text2.Contains("id") && !text2.Contains("steam")) || propertyInfo.GetIndexParameters().Length != 0)
			{
				continue;
			}
			try
			{
				object value3 = propertyInfo.GetValue(value, null);
				if (value3 != null)
				{
					AddCandidateString(candidates, value3.ToString());
				}
			}
			catch
			{
			}
		}
	}

	private static void AddCandidateString(List<string> candidates, string value)
	{
		string text = NormalizeSteamId(value);
		if (!string.IsNullOrEmpty(text) && !candidates.Contains(text))
		{
			candidates.Add(text);
		}
	}

	private static string NormalizeSteamId(string value)
	{
		if (string.IsNullOrEmpty(value))
		{
			return string.Empty;
		}
		string text = string.Empty;
		for (int i = 0; i < value.Length; i++)
		{
			char c = value[i];
			if (char.IsDigit(c))
			{
				text += c;
				continue;
			}
			if (text.Length >= 15)
			{
				return text;
			}
			text = string.Empty;
		}
		if (text.Length >= 15)
		{
			return text;
		}
		return string.Empty;
	}

	private static object GetZNetInstance()
	{
		try
		{
			Type typeFromHandle = typeof(ZNet);
			FieldInfo field = typeFromHandle.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				object value = field.GetValue(null);
				if (value != null)
				{
					return value;
				}
			}
			PropertyInfo property = typeFromHandle.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				object value2 = property.GetValue(null, null);
				if (value2 != null)
				{
					return value2;
				}
			}
			return Object.FindObjectOfType(typeFromHandle);
		}
		catch
		{
			return null;
		}
	}

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

	private static object TryCallNoArgs(object target, string methodName)
	{
		if (target == null)
		{
			return null;
		}
		try
		{
			MethodInfo method = target.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			return (method != null) ? method.Invoke(target, null) : null;
		}
		catch
		{
			return null;
		}
	}

	private static void AddSteamworksCandidate(List<string> candidates)
	{
		try
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType("Steamworks.SteamUser");
				if (!(type == null))
				{
					MethodInfo method = type.GetMethod("GetSteamID", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
					if (!(method == null))
					{
						object value = method.Invoke(null, null);
						AddCandidate(candidates, value);
					}
				}
			}
		}
		catch
		{
		}
	}

	private static void AddKnownTypeCandidates(List<string> candidates)
	{
		try
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type[] array = SafeGetTypes(assemblies[i]);
				foreach (Type type in array)
				{
					string text = type.Name.ToLowerInvariant();
					if (text.Contains("platform") || text.Contains("steam") || text.Contains("playfab"))
					{
						object staticInstance = GetStaticInstance(type);
						if (staticInstance != null)
						{
							AddCandidate(candidates, TryCallNoArgs(staticInstance, "GetLocalUserId"));
							AddCandidate(candidates, TryCallNoArgs(staticInstance, "GetLocalUserID"));
							AddCandidate(candidates, TryCallNoArgs(staticInstance, "GetLocalUser"));
							AddCandidate(candidates, TryCallNoArgs(staticInstance, "GetUserID"));
							AddCandidate(candidates, TryCallNoArgs(staticInstance, "GetUID"));
							AddCandidate(candidates, TryCallNoArgs(staticInstance, "GetSteamID"));
							AddCandidate(candidates, GetFieldValue(staticInstance, "m_steamID"));
							AddCandidate(candidates, GetFieldValue(staticInstance, "m_userID"));
						}
					}
				}
			}
		}
		catch
		{
		}
	}

	private static Type[] SafeGetTypes(Assembly assembly)
	{
		try
		{
			return assembly.GetTypes();
		}
		catch
		{
			return new Type[0];
		}
	}

	private static object GetStaticInstance(Type type)
	{
		try
		{
			FieldInfo field = type.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				object value = field.GetValue(null);
				if (value != null)
				{
					return value;
				}
			}
			PropertyInfo property = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				object value2 = property.GetValue(null, null);
				if (value2 != null)
				{
					return value2;
				}
			}
		}
		catch
		{
		}
		return null;
	}
}
[HarmonyPatch(typeof(Character), "OnDeath")]
public static class RunebornBossKillMessagesPatch
{
	private static string _lastBossKey = string.Empty;

	private static float _lastBossMessageTime;

	private static void Postfix(Character __instance)
	{
		if ((Object)(object)__instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
		{
			return;
		}
		string bossDisplayName = GetBossDisplayName(((Object)((Component)__instance).gameObject).name);
		if (string.IsNullOrEmpty(bossDisplayName))
		{
			return;
		}
		string text = bossDisplayName.ToLowerInvariant();
		if (_lastBossKey == text && Time.time - _lastBossMessageTime < 8f)
		{
			return;
		}
		_lastBossKey = text;
		_lastBossMessageTime = Time.time;
		((Character)Player.m_localPlayer).Message((MessageType)2, "The Rusty Heathens defeated " + bossDisplayName + "!\nValhalla heard the victory roar.", 0, (Sprite)null);
		try
		{
			ZLog.Log((object)("[RustyHeathensRuneborn] Boss defeated: " + bossDisplayName));
		}
		catch
		{
		}
	}

	private static string GetBossDisplayName(string rawName)
	{
		if (string.IsNullOrEmpty(rawName))
		{
			return string.Empty;
		}
		string text = rawName.ToLowerInvariant();
		if (text.Contains("eikthyr"))
		{
			return "Eikthyr";
		}
		if (text.Contains("gd_king") || text.Contains("theelder"))
		{
			return "The Elder";
		}
		if (text.Contains("bonemass"))
		{
			return "Bonemass";
		}
		if (text.Contains("dragon") || text.Contains("moder"))
		{
			return "Moder";
		}
		if (text.Contains("goblinking") || text.Contains("yagluth"))
		{
			return "Yagluth";
		}
		if (text.Contains("queen") || text.Contains("seekerqueen"))
		{
			return "The Queen";
		}
		if (text.Contains("fader"))
		{
			return "Fader";
		}
		return string.Empty;
	}
}
[HarmonyPatch(typeof(Player), "Awake")]
public static class RunebornWelcomeMessageOncePlayerAwakePatch
{
	private static void Postfix(Player __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && (Object)(object)((Component)__instance).GetComponent<RunebornWelcomeMessageOnce>() == (Object)null)
		{
			((Component)__instance).gameObject.AddComponent<RunebornWelcomeMessageOnce>();
		}
	}
}
public sealed class RunebornWelcomeMessageOnce : MonoBehaviour
{
	private static bool _welcomeShownThisGameSession;

	private Player _player;

	private bool _shown;

	private float _showAt;

	private const string WelcomeText = "Welcome to the Rusty Heathens\nSurvive the chaos. Earn Valhalla.";

	private void Awake()
	{
		_player = ((Component)this).GetComponent<Player>();
		_showAt = Time.time + 5f;
		if (_welcomeShownThisGameSession)
		{
			_shown = true;
		}
	}

	private void Update()
	{
		if (_shown || (Object)(object)_player == (Object)null || (Object)(object)Player.m_localPlayer != (Object)(object)_player || Time.time < _showAt)
		{
			return;
		}
		_shown = true;
		_welcomeShownThisGameSession = true;
		try
		{
			((Character)_player).Message((MessageType)2, "Welcome to the Rusty Heathens\nSurvive the chaos. Earn Valhalla.", 0, (Sprite)null);
		}
		catch
		{
		}
	}
}
[HarmonyPatch(typeof(Player), "Awake")]
public static class RunebornServerReminderPlayerAwakePatch
{
	private static void Postfix(Player __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && (Object)(object)((Component)__instance).GetComponent<RunebornServerReminder>() == (Object)null)
		{
			((Component)__instance).gameObject.AddComponent<RunebornServerReminder>();
		}
	}
}
public sealed class RunebornServerReminder : MonoBehaviour
{
	private static bool _serverReminderShownThisGameSession;

	private Player _player;

	private int _messagesShown;

	private float _nextMessageAt;

	public static bool ServerReminderEnabled = true;

	private const int ReminderRepeatCount = 1;

	private const float ReminderFirstDelay = 16f;

	private const float ReminderRepeatDelay = 6f;

	private const string ReminderText = "RUSTY HEATHENS SERVER\n\nRespect the crew.\nNo stealing.\nNo boss fights without the group.\nHelp with body recovery when you can.\nJoin Discord for rules, events, and updates.\n\nSkal, Heathens!";

	private void Awake()
	{
		_player = ((Component)this).GetComponent<Player>();
		_nextMessageAt = Time.time + 16f;
		if (_serverReminderShownThisGameSession)
		{
			_messagesShown = 1;
		}
	}

	private void Update()
	{
		if (_messagesShown < 1 && ServerReminderEnabled && !((Object)(object)_player == (Object)null) && !((Object)(object)Player.m_localPlayer != (Object)(object)_player) && !(Time.time < _nextMessageAt))
		{
			try
			{
				((Character)_player).Message((MessageType)2, "RUSTY HEATHENS SERVER\n\nRespect the crew.\nNo stealing.\nNo boss fights without the group.\nHelp with body recovery when you can.\nJoin Discord for rules, events, and updates.\n\nSkal, Heathens!", 0, (Sprite)null);
			}
			catch
			{
			}
			_messagesShown++;
			_serverReminderShownThisGameSession = true;
			_nextMessageAt = Time.time + 6f;
		}
	}
}
[HarmonyPatch(typeof(Player), "Awake")]
public static class RunebornRaidWarningsPlayerAwakePatch
{
	private static void Postfix(Player __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && (Object)(object)((Component)__instance).GetComponent<RunebornRaidWarnings>() == (Object)null)
		{
			((Component)__instance).gameObject.AddComponent<RunebornRaidWarnings>();
		}
	}
}
public sealed class RunebornRaidWarnings : 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) && 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.FindObjectOfType(type);
				if (val != (Object)null)
				{
					obj = val;
				}
			}
			if (obj == null)
			{
				return null;
			}
			return GetInstanceField(obj, "m_randomEvent") ?? GetInstanceField(obj, "m_currentRandomEvent") ?? GetInstanceField(obj, "m_event");
		}
		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).Message((MessageType)2, text, 0, (Sprite)null);
		}
		catch
		{
		}
	}
}
[HarmonyPatch(typeof(Player), "Awake")]
public static class RunebornServerComfortPlayerAwakePatch
{
	private static void Postfix(Player __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && (Object)(object)((Component)__instance).GetComponent<RunebornServerComfort>() == (Object)null)
		{
			((Component)__instance).gameObject.AddComponent<RunebornServerComfort>();
		}
	}
}
[HarmonyPatch(typeof(Player), "GetMaxCarryWeight")]
public static class RunebornBodyRecoveryCarryWeightPatch
{
	private static void Postfix(Player __instance, ref float __result)
	{
		if (!((Object)(object)__instance == (Object)null) && !((Object)(object)Player.m_localPlayer != (Object)(object)__instance) && RunebornServerComfort.IsBodyRecoveryActiveForLocalPlayer())
		{
			__result += 150f;
		}
	}
}
[HarmonyPatch(typeof(Character), "UseStamina")]
public static class RunebornBodyRecoveryStaminaUsePatch
{
	private static void Prefix(Character __instance, ref float stamina)
	{
		if (!((Object)(object)__instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && (object)__instance == Player.m_localPlayer)
		{
			if (RunebornServerComfort.IsBodyRecoveryActiveForLocalPlayer())
			{
				stamina *= 0.65f;
			}
			if (RunebornServerComfort.IsRustyRestedActiveForLocalPlayer())
			{
				stamina *= 0.9f;
			}
			if (RunebornServerComfort.IsSeppyBuffActiveForLocalPlayer() && RunebornServerComfort.IsLocalPlayerBlocking())
			{
				stamina *= 0.85f;
			}
			if (RunebornServerComfort.IsXpertBuffActiveForLocalPlayer())
			{
				stamina *= 0.9f;
			}
			if (RunebornServerComfort.IsLocalPlayerInChaosMovementStaminaState())
			{
				stamina *= 0.85f;
			}
			if (RunebornServerComfort.IsWitchyMagicStaminaActiveForLocalPlayer())
			{
				stamina *= 0.9f;
			}
			if (RunebornServerComfort.IsBuildComfortActiveForLocalPlayer())
			{
				stamina *= 0.5f;
			}
		}
	}
}
[HarmonyPatch(typeof(Character), "Damage")]
public static class RunebornSeppyBuffDamageReductionPatch
{
	private static void Prefix(Character __instance, HitData hit)
	{
		if (!((Object)(object)__instance == (Object)null) && hit != null && !((Object)(object)Player.m_localPlayer == (Object)null) && (object)__instance == Player.m_localPlayer && RunebornServerComfort.IsSeppyBuffActiveForLocalPlayer())
		{
			RunebornServerComfort.ScaleHitDamage(hit, 0.9f);
		}
	}
}
[HarmonyPatch(typeof(Character), "Damage")]
public static class RunebornXpertBuffDamageBoostPatch
{
	private static void Prefix(Character __instance, HitData hit)
	{
		if (!((Object)(object)__instance == (Object)null) && hit != null && !((Object)(object)Player.m_localPlayer == (Object)null))
		{
			Character val = RunebornServerComfort.TryGetHitAttacker(hit);
			if (!((Object)(object)val == (Object)null) && (object)val == Player.m_localPlayer && (object)__instance != Player.m_localPlayer && RunebornServerComfort.IsXpertBuffActiveForLocalPlayer())
			{
				RunebornServerComfort.ScaleHitDamage(hit, 1.1f);
			}
		}
	}
}
[HarmonyPatch(typeof(Player), "Update")]
public static class RunebornChaosBringerMovementOnlyPatch
{
	private static void Postfix(Player __instance)
	{
		try
		{
			RunebornServerComfort.ApplyChaosBringerMovementOnly(__instance);
		}
		catch
		{
		}
	}
}
public sealed class RunebornServerComfort : MonoBehaviour
{
	private const string DeathCountKey = "RustyHeathensRuneborn.DeathCount";

	private const string BodyRecoveryExpiresKey = "RustyHeathensRuneborn.BodyRecoveryExpiresUtcTicks";

	private const float BodyRecoverySeconds = 600f;

	private Player _player;

	private bool _wasDead;

	private bool _bodyRecoveryNoticeShown;

	private float _nextCheck;

	private string _deathMessageRepeatText = string.Empty;

	private int _deathMessageRepeatsLeft;

	private float _nextDeathMessageRepeatAt;

	private const int DefaultMaxSelectedBuffs = 2;

	private const string MaxSelectedBuffsKey = "RustyHeathensRuneborn.MaxSelectedBuffs";

	private const string SelectedBuffsKey = "RustyHeathensRuneborn.SelectedBuffs";

	private const string EnabledBuffMaskKey = "RustyHeathensRuneborn.EnabledBuffMask";

	private const int RustyBuffBit = 1;

	private const int SeppyBuffBit = 2;

	private const int XpertBuffBit = 4;

	private const int ChaosBuffBit = 8;

	private const int WitchyBuffBit = 16;

	private const int AllBuffsMask = 31;

	private static readonly Dictionary<int, Dictionary<string, float>> ChaosMovementBaseValues = new Dictionary<int, Dictionary<string, float>>();

	private static int MaxSelectedBuffs => Mathf.Clamp(PlayerPrefs.GetInt("RustyHeathensRuneborn.MaxSelectedBuffs", 2), 1, 3);

	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) && !(Time.time < _nextCheck))
		{
			_nextCheck = Time.time + 0.25f;
			bool flag = IsPlayerDead(_player);
			if (flag && !_wasDead)
			{
				RegisterLocalDeath();
			}
			if (!flag && _wasDead)
			{
				_bodyRecoveryNoticeShown = false;
			}
			_wasDead = flag;
			TryShowBodyRecoveryReminder(flag);
			TryRepeatDeathMessage();
		}
	}

	private void RegisterLocalDeath()
	{
		int num = PlayerPrefs.GetInt("RustyHeathensRuneborn.DeathCount", 0) + 1;
		PlayerPrefs.SetInt("RustyHeathensRuneborn.DeathCount", num);
		PlayerPrefs.SetString("RustyHeathensRuneborn.BodyRecoveryExpiresUtcTicks", DateTime.UtcNow.AddSeconds(600.0).Ticks.ToString());
		PlayerPrefs.Save();
		string funnyDeathMessage = GetFunnyDeathMessage(num);
		string text = "Death #" + num + "\n" + funnyDeathMessage + "\nBody Recovery ready for 10 minutes.\n+150 carry weight, less stamina used.";
		ShowCenter(text);
		_deathMessageRepeatText = text;
		_deathMessageRepeatsLeft = 2;
		_nextDeathMessageRepeatAt = Time.time + 3.5f;
		try
		{
			ZLog.Log((object)("[RustyHeathensRuneborn] Local death count: " + num));
		}
		catch
		{
		}
	}

	public static string PreviewNextFunnyDeathMessage(int currentDeathCount)
	{
		return GetFunnyDeathMessage(currentDeathCount + 1);
	}

	private static string GetFunnyDeathMessage(int deathCount)
	{
		if (deathCount <= 1)
		{
			return "First blood. Valhalla is watching.";
		}
		switch (deathCount)
		{
		case 10:
			return "Ten deaths. The Heathens are officially warming up.";
		case 25:
			return "Twenty-five deaths. Odin filed a report.";
		case 50:
			return "Fifty deaths. The death counter needs a bigger boat.";
		case 100:
			return "One hundred deaths. Seppy would be proud.";
		default:
		{
			string[] array = new string[20]
			{
				"Another shortcut to Valhalla.", "Odin saw that. So did chat.", "Body recovery team, saddle up.", "The ground won that fight.", "Your gear is now on a side quest.", "The Rusty Heathens death counter demands tribute.", "Not a death, just aggressive fast travel.", "That was tactical. Probably.", "The trolls are taking notes.", "Somebody clip that.",
				"Valheim said no.", "The corpse run begins.", "Rusty Heathens rule one: do not panic. Too late.", "The swamp sends its regards.", "The mountain claimed another kneecap.", "Ashlands heard you were feeling confident.", "The Plains mosquito has entered the chat.", "Mistlands visibility: zero. Survival odds: also zero.", "A brave death. A questionable plan.", "The gear is fine. The owner, less so."
			};
			int num = Mathf.Abs(deathCount - 2) % array.Length;
			return array[num];
		}
		}
	}

	private void TryRepeatDeathMessage()
	{
		if (_deathMessageRepeatsLeft > 0)
		{
			if (string.IsNullOrEmpty(_deathMessageRepeatText))
			{
				_deathMessageRepeatsLeft = 0;
			}
			else if (!(Time.time < _nextDeathMessageRepeatAt))
			{
				ShowCenter(_deathMessageRepeatText);
				_deathMessageRepeatsLeft--;
				_nextDeathMessageRepeatAt = Time.time + 3.5f;
			}
		}
	}

	private void TryShowBodyRecoveryReminder(bool isDead)
	{
		if (!isDead && !_bodyRecoveryNoticeShown)
		{
			float bodyRecoverySecondsLeft = GetBodyRecoverySecondsLeft();
			if (!(bodyRecoverySecondsLeft <= 0f))
			{
				_bodyRecoveryNoticeShown = true;
				ShowCenter("Body Recovery Active\n" + Mathf.CeilToInt(bodyRecoverySecondsLeft / 60f) + " minutes to get your gear.");
			}
		}
	}

	public static bool IsSeppyBuffActiveForLocalPlayer()
	{
		if (IsBuffSelected("seppy"))
		{
			return IsLocalPlayerRested();
		}
		return false;
	}

	public static bool IsLocalPlayerBlocking()
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return false;
		}
		try
		{
			MethodInfo method = typeof(Humanoid).GetMethod("IsBlocking", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method != null)
			{
				object obj = method.Invoke(localPlayer, null);
				if (obj is bool)
				{
					return (bool)obj;
				}
			}
		}
		catch
		{
		}
		return IsShieldEquipped(localPlayer);
	}

	private static bool IsShieldEquipped(Player player)
	{
		if ((Object)(object)player == (Object)null)
		{
			return false;
		}
		try
		{
			MethodInfo method = typeof(Humanoid).GetMethod("GetLeftItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return false;
			}
			object obj = method.Invoke(player, null);
			if (obj == null)
			{
				return false;
			}
			string text = GetItemSharedName(obj).ToLowerInvariant();
			return text.Contains("shield") || text.Contains("buckler") || text.Contains("tower");
		}
		catch
		{
			return false;
		}
	}

	public static void ScaleHitDamage(HitData hit, float scale)
	{
		if (hit == null)
		{
			return;
		}
		try
		{
			object fieldValue = GetFieldValue(hit, "m_damage");
			if (fieldValue != null)
			{
				ScaleDamageTypesObject(fieldValue, scale);
			}
		}
		catch
		{
		}
	}

	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 void ScaleDamageTypesObject(object damageTypes, float scale)
	{
		if (damageTypes == null)
		{
			return;
		}
		FieldInfo[] fields = damageTypes.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (!(fieldInfo.FieldType != typeof(float)))
			{
				string text = fieldInfo.Name.ToLowerInvariant();
				if (text.Contains("damage") || text.Contains("blunt") || text.Contains("slash") || text.Contains("pierce") || text.Contains("chop") || text.Contains("pickaxe") || text.Contains("fire") || text.Contains("frost") || text.Contains("lightning") || text.Contains("poison") || text.Contains("spirit"))
				{
					float num = (float)fieldInfo.GetValue(damageTypes);
					fieldInfo.SetValue(damageTypes, num * scale);
				}
			}
		}
	}

	public static bool IsXpertBuffActiveForLocalPlayer()
	{
		if (IsBuffSelected("xpert") && IsLocalPlayerRested())
		{
			return IsLocalPlayerUsingBerserkerWeapon();
		}
		return false;
	}

	public static bool IsLocalPlayerUsingBerserkerWeapon()
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return false;
		}
		try
		{
			MethodInfo method = typeof(Humanoid).GetMethod("GetRightItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return false;
			}
			object obj = method.Invoke(localPlayer, null);
			if (obj == null)
			{
				return false;
			}
			string text = GetItemSharedName(obj).ToLowerInvariant();
			return text.Contains("axe") || text.Contains("battleaxe") || text.Contains("sword") || text.Contains("mace") || text.Contains("club") || text.Contains("knife") || text.Contains("atgeir") || text.Contains("spear");
		}
		catch
		{
			return false;
		}
	}

	public static Character TryGetHitAttacker(HitData hit)
	{
		if (hit == null)
		{
			return null;
		}
		try
		{
			MethodInfo method = ((object)hit).GetType().GetMethod("GetAttacker", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (method == null)
			{
				return null;
			}
			object? obj = method.Invoke(hit, null);
			return (Character)((obj is Character) ? obj : null);
		}
		catch
		{
			return null;
		}
	}

	public static bool IsChaosBringerBuffActiveForLocalPlayer()
	{
		if (IsBuffSelected("chaos"))
		{
			return IsLocalPlayerRested();
		}
		return false;
	}

	public static void ApplyChaosBringerMovementOnly(Player player)
	{
		if ((Object)(object)player == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || player != Player.m_localPlayer)
		{
			return;
		}
		int instanceID = ((Object)player).GetInstanceID();
		bool flag = IsChaosBringerBuffActiveForLocalPlayer();
		string[] array = new string[6] { "m_walkSpeed", "m_runSpeed", "m_crouchSpeed", "m_swimSpeed", "m_jumpForce", "m_jumpForceForward" };
		if (flag)
		{
			if (!ChaosMovementBaseValues.ContainsKey(instanceID))
			{
				ChaosMovementBaseValues[instanceID] = new Dictionary<string, float>();
			}
			Dictionary<string, float> dictionary = ChaosMovementBaseValues[instanceID];
			string[] array2 = array;
			foreach (string text in array2)
			{
				FieldInfo fieldInfo = FindChaosFloatField(player, text);
				if (!(fieldInfo == null))
				{
					if (!dictionary.ContainsKey(text))
					{
						dictionary[text] = (float)fieldInfo.GetValue(player);
					}
					float num = 1.1f;
					if (text == "m_crouchSpeed")
					{
						num = 1.2f;
					}
					if (text == "m_jumpForce" || text == "m_jumpForceForward")
					{
						num = 1.12f;
					}
					fieldInfo.SetValue(player, dictionary[text] * num);
				}
			}
		}
		else
		{
			RestoreChaosBringerMovementOnly(player, instanceID);
		}
	}

	private static void RestoreChaosBringerMovementOnly(Player player, int playerKey)
	{
		if ((Object)(object)player == (Object)null || !ChaosMovementBaseValues.ContainsKey(playerKey))
		{
			return;
		}
		foreach (KeyValuePair<string, float> item in ChaosMovementBaseValues[playerKey])
		{
			FieldInfo fieldInfo = FindChaosFloatField(player, item.Key);
			if (fieldInfo != null)
			{
				fieldInfo.SetValue(player, item.Value);
			}
		}
		ChaosMovementBaseValues.Remove(playerKey);
	}

	private static FieldInfo FindChaosFloatField(object target, string fieldName)
	{
		if (target == null || string.IsNullOrEmpty(fieldName))
		{
			return null;
		}
		Type type = target.GetType();
		while (type != null)
		{
			FieldInfo field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null && field.FieldType == typeof(float))
			{
				return field;
			}
			type = type.BaseType;
		}
		return null;
	}

	public static bool IsLocalPlayerInChaosMovementStaminaState()
	{
		if (!IsChaosBringerBuffActiveForLocalPlayer())
		{
			return false;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return false;
		}
		if (!TryCallChaosBool(localPlayer, "IsSwimming") && !TryCallChaosBool(localPlayer, "InDodge") && !TryCallChaosBool(localPlayer, "IsDodgeInvincible") && !TryGetChaosBoolField(localPlayer, "m_dodgeInvincible"))
		{
			return TryGetChaosBoolField(localPlayer, "m_dodging");
		}
		return true;
	}

	private static bool TryCallChaosBool(object target, string methodName)
	{
		if (target == null || string.IsNullOrEmpty(methodName))
		{
			return false;
		}
		Type type = target.GetType();
		while (type != null)
		{
			MethodInfo method = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (method != null && method.ReturnType == typeof(bool))
			{
				return (bool)method.Invoke(target, null);
			}
			type = type.BaseType;
		}
		return false;
	}

	private static bool TryGetChaosBoolField(object target, string fieldName)
	{
		if (target == null || string.IsNullOrEmpty(fieldName))
		{
			return false;
		}
		Type type = target.GetType();
		while (type != null)
		{
			FieldInfo field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null && field.FieldType == typeof(bool))
			{
				return (bool)field.GetValue(target);
			}
			type = type.BaseType;
		}
		return false;
	}

	public static bool IsWitchyBuffActiveForLocalPlayer()
	{
		if (IsBuffSelected("witchy"))
		{
			return IsLocalPlayerRested();
		}
		return false;
	}

	public static bool IsWitchyMagicStaminaActiveForLocalPlayer()
	{
		if (IsWitchyBuffActiveForLocalPlayer())
		{
			return IsLocalPlayerUsingWitchyWeapon();
		}
		return false;
	}

	public static bool IsLocalPlayerUsingWitchyWeapon()
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return false;
		}
		try
		{
			MethodInfo method = typeof(Humanoid).GetMethod("GetRightItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return false;
			}
			object obj = method.Invoke(localPlayer, null);
			if (obj == null)
			{
				return false;
			}
			string text = GetWitchyItemName(obj).ToLowerInvariant();
			return text.Contains("staff") || text.Contains("magic") || text.Contains("eitr") || text.Contains("wand") || text.Contains("scepter") || text.Contains("trollstav") || text.Contains("deadraiser") || text.Contains("protection") || text.Contains("embers") || text.Contains("frost");
		}
		catch
		{
			return false;
		}
	}

	private static string GetWitchyItemName(object item)
	{
		if (item == null)
		{
			return string.Empty;
		}
		try
		{
			FieldInfo field = item.GetType().GetField("m_shared", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				return item.ToString();
			}
			object value = field.GetValue(item);
			if (value == null)
			{
				return item.ToString();
			}
			FieldInfo field2 = value.GetType().GetField("m_name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field2 == null)
			{
				return value.ToString();
			}
			object value2 = field2.GetValue(value);
			if (value2 == null)
			{
				return string.Empty;
			}
			return value2.ToString();
		}
		catch
		{
			return string.Empty;
		}
	}

	public static bool IsBuildComfortActiveForLocalPlayer()
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return false;
		}
		try
		{
			MethodInfo method = typeof(Humanoid).GetMethod("GetRightItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method == null)
			{
				return false;
			}
			object obj = method.Invoke(localPlayer, null);
			if (obj == null)
			{
				return false;
			}
			string text = GetItemSharedName(obj).ToLowerInvariant();
			return text.Contains("hammer") || text.Contains("hoe") || text.Contains("cultivator");
		}
		catch
		{
			return false;
		}
	}

	private static string GetItemSharedName(object item)
	{
		if (item == null)
		{
			return string.Empty;
		}
		FieldInfo field = item.GetType().GetField("m_shared", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		object obj = ((field != null) ? field.GetValue(item) : null);
		if (obj == null)
		{
			return string.Empty;
		}
		FieldInfo field2 = obj.GetType().GetField("m_name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		object obj2 = ((field2 != n