Decompiled source of SinnerPeak v1.0.0

plugins/StealthJug.SinnerPeak.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak.Afflictions;
using Photon.Pun;
using Photon.Realtime;
using SinnerPeak;
using SinnerPeak.Core;
using SinnerPeak.Groups;
using SinnerPeak.Helpers;
using SinnerPeak.Networking;
using SinnerPeak.Patches;
using SinnerPeak.Revive;
using SinnerPeak.UI;
using Steamworks;
using TMPro;
using UnityEngine;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("StealthJug.SinnerPeak")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+eef72ddc960bc49782808e9b7e8059d05a28d1cd")]
[assembly: AssemblyProduct("StealthJug.SinnerPeak")]
[assembly: AssemblyTitle("SinnerPeak")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
[HarmonyPatch]
public static class Patch_LobbyLoadingFinished
{
	private static bool joinLinkSent;

	private static MethodBase TargetMethod()
	{
		Type typeFromHandle = typeof(LoadingScreen);
		Type[] nestedTypes = typeFromHandle.GetNestedTypes(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		Type type = null;
		Type[] array = nestedTypes;
		foreach (Type type2 in array)
		{
			if (type2.Name.Contains("LoadingRoutine"))
			{
				type = type2;
				break;
			}
		}
		if (type == null)
		{
			Plugin.Log.LogError((object)"[SinnerPeak] ERROR: Could not find LoadingRoutine state machine!");
			return null;
		}
		return type.GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.NonPublic);
	}

	[HarmonyPostfix]
	private static void AfterLoadingFinished(object __instance)
	{
		FieldInfo field = __instance.GetType().GetField("<>1__state", BindingFlags.Instance | BindingFlags.NonPublic);
		if (field == null)
		{
			return;
		}
		int num = (int)field.GetValue(__instance);
		if (num == -1 && PhotonNetwork.IsMasterClient && !joinLinkSent)
		{
			joinLinkSent = true;
			string joinURI = SteamJoinLink.GetJoinURI();
			Plugin.Log.LogInfo((object)("[SinnerPeak] Steam Join Link: " + joinURI));
			if (!string.IsNullOrWhiteSpace(joinURI))
			{
				string message = "**Join the game:**\t" + joinURI + "\n";
				Webhook.Send(message);
			}
		}
	}
}
public class SinnerPeakRuntime : MonoBehaviour
{
	private int f;

	private void Update()
	{
		if (++f == 10)
		{
			f = 0;
			Patch_Biome.UpdateCampfireCheck();
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace SinnerPeak
{
	[BepInPlugin("stealthjug.sinnerpeak", "SinnerPeak", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private Harmony _harmony;

		public static ConfigEntry<bool> ShowLeaderboard;

		public static ConfigEntry<bool> UseGroupLeaderboard;

		public static ConfigEntry<KeyboardShortcut> ToggleLeaderboardKey;

		public static ConfigEntry<KeyboardShortcut> TogglePointsKey;

		public static ConfigEntry<KeyboardShortcut> ToggleGroupManagerKey;

		public static ConfigEntry<int> PointsFirst;

		public static ConfigEntry<int> PointsSecond;

		public static ConfigEntry<int> PointsThird;

		public static ConfigEntry<string> FinishWebhook;

		public static bool ShowPointsMode = false;

		public static Dictionary<int, int> TotalPoints = new Dictionary<int, int>();

		public static string CurrentBiomeName = "UNKNOWN";

		public static ConfigEntry<float> ReviveRadius;

		public static ConfigEntry<int> MaxTokens;

		public static ConfigEntry<int> StartTokens;

		public static ConfigEntry<KeyboardShortcut> ReviveKey;

		public void Awake()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Expected O, but got Unknown
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Expected O, but got Unknown
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Expected O, but got Unknown
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Expected O, but got Unknown
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Expected O, but got Unknown
			//IL_029c: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"SinnerPeak loading…");
			ShowLeaderboard = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowLeaderboard", true, "Whether the leaderboard is visible.");
			UseGroupLeaderboard = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "UseGroupLeaderboard", false, "Enable group-based leaderboard mode.");
			ToggleLeaderboardKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keys", "ToggleLeaderboard", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Toggle leaderboard window.");
			TogglePointsKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keys", "TogglePoints", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Toggle between normal and points leaderboard");
			ToggleGroupManagerKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keys", "ToggleGroupManager", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Toggle group manager UI (host only)");
			PointsFirst = ((BaseUnityPlugin)this).Config.Bind<int>("Points", "FirstPlace", 5, "Points for finishing 1st");
			PointsSecond = ((BaseUnityPlugin)this).Config.Bind<int>("Points", "SecondPlace", 3, "Points for finishing 2nd");
			PointsThird = ((BaseUnityPlugin)this).Config.Bind<int>("Points", "ThirdPlace", 1, "Points for finishing 3rd");
			FinishWebhook = ((BaseUnityPlugin)this).Config.Bind<string>("Webhook", "FinishWebhook", "", "Webhook URL for biome finish notifications. Leave empty to disable.");
			ReviveRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Revive", "ReviveRadius", 50f, "Maximum distance (in meters) to revive a teammate. (HOST ONLY)");
			MaxTokens = ((BaseUnityPlugin)this).Config.Bind<int>("Revive", "MaxTokens", 3, "Maximum revive tokens a group can hold. (HOST ONLY)");
			StartTokens = ((BaseUnityPlugin)this).Config.Bind<int>("Revive", "StartTokens", 1, "Number of revive tokens each group starts with. (HOST ONLY)");
			ReviveKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Revive", "ReviveKey", new KeyboardShortcut((KeyCode)102, Array.Empty<KeyCode>()), "Key used for modded revive (F-hold revive).");
			GameObject val = new GameObject("SinnerPeak_UI");
			val.AddComponent<LeaderboardUI>();
			val.AddComponent<GroupManagerUI>();
			Object.DontDestroyOnLoad((Object)(object)val);
			_harmony = new Harmony("stealthjug.sinnerpeak");
			_harmony.PatchAll();
			GameObject val2 = new GameObject("SinnerPeak_Runtime");
			val2.AddComponent<SinnerPeakRuntime>();
			val2.AddComponent<ReviveRuntime>();
			Object.DontDestroyOnLoad((Object)(object)val2);
			GameObject val3 = new GameObject("NetworkGroupSync");
			PhotonView val4 = val3.AddComponent<PhotonView>();
			val4.ViewID = 999999900;
			val3.AddComponent<NetworkGroupSync>();
			Object.DontDestroyOnLoad((Object)(object)val3);
			Player localPlayer = PhotonNetwork.LocalPlayer;
			Hashtable val5 = new Hashtable();
			((Dictionary<object, object>)val5).Add((object)"SP_Modded", (object)true);
			localPlayer.SetCustomProperties(val5, (Hashtable)null, (WebFlags)null);
			((Component)this).gameObject.AddComponent<ReviveBootstrap>();
			Log.LogInfo((object)"SinnerPeak initialized successfully.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Log.LogInfo((object)"SinnerPeak unloaded.");
		}
	}
}
namespace SinnerPeak.UI
{
	public class GroupManagerUI : MonoBehaviour
	{
		private bool open;

		private GUIStyle richToggle;

		private Rect windowRect = new Rect(200f, 200f, 560f, 720f);

		private Vector2 scrollGroups;

		private Vector2 scrollPlayers;

		private string newGroupName = "";

		private int newGroupSkinIndex;

		private bool dropdownOpen;

		private int selectedGroupIndex;

		private GUIStyle skinButtonStyle;

		private GUIStyle skinButtonSelectedStyle;

		private GUIStyle richLabel;

		private GUIStyle headerLabel;

		private int tabIndex;

		private readonly string[] tabs = new string[3] { "Groups", "Host Tools", "Players" };

		private int autoScrollTargetIndex = -1;

		private int selectedHostPlayerIndex;

		private int selectedHostGroupIndex;

		private List<Character> cachedCharacters = new List<Character>();

		private string[] cachedPlayerNames = Array.Empty<string>();

		private float nextPlayerCacheTime;

		private bool hostPlayerDropdownOpen;

		private bool groupCacheInitialized;

		private int lastGroupCount = -1;

		private string[] cachedGroupNames = Array.Empty<string>();

		private bool hostGroupDropdownOpen;

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Plugin.ToggleGroupManagerKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				open = !open;
			}
		}

		private void OnGUI()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			if (!open)
			{
				return;
			}
			EnsureStyles();
			if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
			{
				windowRect = GUI.Window(99123, windowRect, new WindowFunction(DrawLoadingWindow), "Group Manager");
				return;
			}
			int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
			string groupOfPlayer = GroupManager.GetGroupOfPlayer(actorNumber);
			bool isMasterClient = PhotonNetwork.IsMasterClient;
			bool flag = GroupManager.IsSpectatorGroup(groupOfPlayer);
			if (isMasterClient || flag)
			{
				windowRect = GUI.Window(99123, windowRect, new WindowFunction(DrawWindow), "Group Manager");
			}
		}

		private void DrawLoadingWindow(int id)
		{
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			GUILayout.Space(20f);
			GUILayout.Label("<b>Loading…</b>", headerLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(20f);
			GUILayout.EndVertical();
			GUI.DragWindow();
		}

		private void EnsureStyles()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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)
			//IL_0050: Expected O, but got Unknown
			if (richLabel == null)
			{
				richLabel = new GUIStyle(GUI.skin.label)
				{
					richText = true
				};
			}
			if (headerLabel == null)
			{
				headerLabel = new GUIStyle(GUI.skin.label)
				{
					richText = true,
					fontSize = 14
				};
			}
		}

		private void DrawWindow(int id)
		{
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			GUILayout.Space(8f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			for (int i = 0; i < tabs.Length; i++)
			{
				GUIStyle val = ((i == tabIndex) ? GUI.skin.button : GUI.skin.box);
				if (GUILayout.Button(tabs[i], val, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
				{
					tabIndex = i;
				}
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(10f);
			if (tabIndex == 0)
			{
				DrawGroupsTab();
			}
			else if (tabIndex == 1)
			{
				DrawHostToolsTab();
			}
			else
			{
				DrawModdedPlayersTab();
			}
			GUILayout.EndVertical();
			GUI.DragWindow();
		}

		private void EnsurePlayerCache()
		{
			if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
			{
				cachedCharacters.Clear();
				cachedPlayerNames = Array.Empty<string>();
				nextPlayerCacheTime = Time.time + 3f;
			}
			else
			{
				if (Time.time < nextPlayerCacheTime)
				{
					return;
				}
				cachedCharacters = PlayerHandler.GetAllPlayerCharacters() ?? new List<Character>();
				int count = cachedCharacters.Count;
				cachedPlayerNames = new string[count];
				for (int i = 0; i < count; i++)
				{
					Character val = cachedCharacters[i];
					if ((Object)(object)val == (Object)null || (Object)(object)((MonoBehaviourPun)val).photonView == (Object)null || ((MonoBehaviourPun)val).photonView.Owner == null)
					{
						cachedPlayerNames[i] = "Unknown";
						continue;
					}
					Player owner = ((MonoBehaviourPun)val).photonView.Owner;
					cachedPlayerNames[i] = owner.NickName + " (" + owner.ActorNumber + ")";
				}
				nextPlayerCacheTime = Time.time + 3f;
			}
		}

		private void EnsureGroupCache()
		{
			int count = GroupManager.Groups.Count;
			if (groupCacheInitialized && count == lastGroupCount)
			{
				return;
			}
			Dictionary<string, Group>.KeyCollection keys = GroupManager.Groups.Keys;
			cachedGroupNames = new string[keys.Count];
			int num = 0;
			foreach (string item in keys)
			{
				cachedGroupNames[num++] = item;
			}
			lastGroupCount = count;
			groupCacheInitialized = true;
		}

		private Character GetRealCharacter(int actor)
		{
			Character result = null;
			foreach (Character allPlayerCharacter in PlayerHandler.GetAllPlayerCharacters())
			{
				if (!((Object)(object)allPlayerCharacter == (Object)null) && !((Object)(object)((MonoBehaviourPun)allPlayerCharacter).photonView == (Object)null) && ((MonoBehaviourPun)allPlayerCharacter).photonView.OwnerActorNr == actor && (!((Object)(object)allPlayerCharacter.data != (Object)null) || !allPlayerCharacter.data.dead))
				{
					result = allPlayerCharacter;
					break;
				}
			}
			return result;
		}

		private void DrawGroupsTab()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			Color color = GUI.color;
			GUI.color = (Plugin.UseGroupLeaderboard.Value ? Color.green : Color.white);
			if (richToggle == null)
			{
				richToggle = new GUIStyle(GUI.skin.toggle)
				{
					richText = true,
					fontSize = 14
				};
			}
			bool flag = GUILayout.Toggle(Plugin.UseGroupLeaderboard.Value, "<b>Enable Group-Based Leaderboard</b>", richToggle, Array.Empty<GUILayoutOption>());
			GUI.color = color;
			if (flag != Plugin.UseGroupLeaderboard.Value)
			{
				Plugin.UseGroupLeaderboard.Value = flag;
				NetworkGroupSync.RequestSetGroupLeaderboard(flag);
			}
			GUILayout.Space(12f);
			GUILayout.Label("<b>Create Group</b>", headerLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			newGroupName = GUILayout.TextField(newGroupName, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(220f) });
			GUILayout.Label("Color (Skin):", richLabel, Array.Empty<GUILayoutOption>());
			newGroupSkinIndex = SkinSelector(newGroupSkinIndex);
			if (GUILayout.Button("Create Group", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(25f) }) && !string.IsNullOrWhiteSpace(newGroupName))
			{
				Color skinColor = GetSkinColor(newGroupSkinIndex);
				NetworkGroupSync.RequestCreateGroup(newGroupName, skinColor, newGroupSkinIndex);
				newGroupName = "";
			}
			GUILayout.Space(15f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(270f),
				GUILayout.ExpandHeight(true)
			});
			GUILayout.Label("<b>Groups</b>", headerLabel, Array.Empty<GUILayoutOption>());
			scrollGroups = GUILayout.BeginScrollView(scrollGroups, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			DrawGroupList();
			GUILayout.EndScrollView();
			GUILayout.Space(12f);
			GUILayout.EndVertical();
			GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(270f),
				GUILayout.ExpandHeight(true)
			});
			GUILayout.Label("<b>Players</b>", headerLabel, Array.Empty<GUILayoutOption>());
			DrawGroupDropdown();
			scrollPlayers = GUILayout.BeginScrollView(scrollPlayers, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			EnsurePlayerCache();
			for (int i = 0; i < cachedCharacters.Count; i++)
			{
				Character val = cachedCharacters[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)((MonoBehaviourPun)val).photonView == (Object)null) && ((MonoBehaviourPun)val).photonView.Owner != null)
				{
					Player owner = ((MonoBehaviourPun)val).photonView.Owner;
					int actorNumber = owner.ActorNumber;
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Label(owner.NickName + " (" + actorNumber + ")", Array.Empty<GUILayoutOption>());
					if (GUILayout.Button("Add", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }))
					{
						string groupNameByIndex = GetGroupNameByIndex(selectedGroupIndex);
						NetworkGroupSync.RequestAssignPlayer(actorNumber, groupNameByIndex);
					}
					GUILayout.EndHorizontal();
				}
			}
			GUILayout.EndScrollView();
			GUILayout.Space(12f);
			GUILayout.EndVertical();
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
			HandleAutoScroll();
		}

		private void HandleAutoScroll()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (autoScrollTargetIndex >= 0)
			{
				float num = 110f;
				float num2 = (float)autoScrollTargetIndex * (num + 5f);
				scrollGroups = new Vector2(0f, num2);
				autoScrollTargetIndex = -1;
			}
		}

		private void DrawGroupList()
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			string text = null;
			int? num = null;
			foreach (KeyValuePair<string, Group> group in GroupManager.Groups)
			{
				Group value = group.Value;
				GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
				GUILayout.Label("<b>" + value.Name + "</b>", headerLabel, Array.Empty<GUILayoutOption>());
				GUILayout.Label("Color (Skin):", richLabel, Array.Empty<GUILayoutOption>());
				int num2 = SkinSelector(value.SkinIndex);
				if (num2 != value.SkinIndex)
				{
					value.SkinIndex = num2;
					Color skinColor = GetSkinColor(num2);
					NetworkGroupSync.RequestSetGroupColor(value.Name, skinColor, num2);
				}
				GUILayout.Space(5f);
				GUILayout.Label("Members:", richLabel, Array.Empty<GUILayoutOption>());
				foreach (int member in value.Members)
				{
					Room currentRoom = PhotonNetwork.CurrentRoom;
					Player val = ((currentRoom != null) ? currentRoom.GetPlayer(member, false) : null);
					string arg = ((val != null) ? val.NickName : $"Player {member}");
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Label($"{arg} ({member})", Array.Empty<GUILayoutOption>());
					if (GUILayout.Button("Remove", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
					{
						num = member;
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.Space(5f);
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.FlexibleSpace();
				if (!GroupManager.IsSpectatorGroup(value.Name) && GUILayout.Button("Delete Group", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) }))
				{
					text = value.Name;
				}
				GUILayout.EndHorizontal();
				GUILayout.EndVertical();
				GUILayout.Space(5f);
			}
			if (num.HasValue)
			{
				NetworkGroupSync.RequestAssignPlayer(num.Value, "Ungrouped");
			}
			if (text == null)
			{
				return;
			}
			List<int> list = new List<int>(GroupManager.Groups[text].Members);
			foreach (int item in list)
			{
				NetworkGroupSync.RequestAssignPlayer(item, "Ungrouped");
			}
			ReviveTokenManager.DeleteGroupToken(text);
			NetworkGroupSync.RequestDeleteGroup(text);
		}

		private void DrawHostToolsTab()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.Label("<b>Host Tools</b>", headerLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			scrollPlayers = GUILayout.BeginScrollView(scrollPlayers, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			EnsurePlayerCache();
			List<Character> list = cachedCharacters;
			string[] array = cachedPlayerNames;
			GUILayout.Label("<b>Select Player</b>", headerLabel, Array.Empty<GUILayoutOption>());
			if (array.Length == 0)
			{
				GUILayout.Label("No players found.", richLabel, Array.Empty<GUILayoutOption>());
				GUILayout.EndScrollView();
				return;
			}
			if (GUILayout.Button("Player: " + array[selectedHostPlayerIndex], (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(25f) }))
			{
				hostPlayerDropdownOpen = !hostPlayerDropdownOpen;
			}
			if (hostPlayerDropdownOpen)
			{
				GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
				for (int i = 0; i < array.Length; i++)
				{
					if (GUILayout.Button(array[i], Array.Empty<GUILayoutOption>()))
					{
						selectedHostPlayerIndex = i;
						hostPlayerDropdownOpen = false;
					}
				}
				GUILayout.EndVertical();
			}
			GUILayout.Space(10f);
			if (selectedHostPlayerIndex < 0 || selectedHostPlayerIndex >= list.Count)
			{
				selectedHostPlayerIndex = 0;
			}
			int ownerActorNr = ((MonoBehaviourPun)list[selectedHostPlayerIndex]).photonView.OwnerActorNr;
			Character val = GetRealCharacter(ownerActorNr);
			if ((Object)(object)val == (Object)null)
			{
				val = list[selectedHostPlayerIndex];
			}
			if ((Object)(object)val == (Object)null || (Object)(object)((MonoBehaviourPun)val).photonView == (Object)null || ((MonoBehaviourPun)val).photonView.Owner == null)
			{
				GUILayout.Label("Player not ready.", richLabel, Array.Empty<GUILayoutOption>());
				GUILayout.EndScrollView();
				return;
			}
			bool flag = (Object)(object)val.data != (Object)null && val.data.dead;
			GUILayout.Space(20f);
			GUILayout.Label("<b>Player Management</b>", headerLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(5f);
			if (flag)
			{
				if (GUILayout.Button("Revive", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
				{
					RevivePlayer(val);
				}
			}
			else
			{
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				if (GUILayout.Button("To Player", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
				{
					TeleportToPlayer(val);
				}
				if (GUILayout.Button("Player To Me", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
				{
					TeleportPlayerToMe(val);
				}
				GUILayout.EndHorizontal();
				if (GUILayout.Button("To Biome End", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
				{
					TeleportPlayerToBiomeEnd(val);
				}
				if ((Object)(object)Singleton<MapHandler>.Instance != (Object)null && GUILayout.Button("Revive", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
				{
					RevivePlayer(val);
				}
			}
			GUILayout.Space(20f);
			GUILayout.Label("<b>Leaderboard Flags</b>", headerLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(5f);
			if (!Leaderboard.TryGetStats(ownerActorNr, out var stats))
			{
				GUILayout.Label("No stats found for this player.", richLabel, Array.Empty<GUILayoutOption>());
			}
			else
			{
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				if (GUILayout.Button("Add DNF", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
				{
					stats.DNF = true;
				}
				if (GUILayout.Button("Remove DNF", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
				{
					stats.DNF = false;
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.Space(20f);
			GUILayout.Label("<b>Global Revive</b>", headerLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(5f);
			if (GUILayout.Button("Revive All Players", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				ReviveAllPlayers();
			}
			GUILayout.Space(20f);
			GUILayout.Label("<b>Group Management</b>", headerLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(5f);
			EnsureGroupCache();
			string[] array2 = cachedGroupNames;
			if (array2.Length == 0)
			{
				GUILayout.Label("No groups created.", richLabel, Array.Empty<GUILayoutOption>());
				GUILayout.EndScrollView();
				return;
			}
			if (GUILayout.Button("Group: " + array2[selectedHostGroupIndex], (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(25f) }))
			{
				hostGroupDropdownOpen = !hostGroupDropdownOpen;
			}
			if (hostGroupDropdownOpen)
			{
				GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
				for (int j = 0; j < array2.Length; j++)
				{
					if (GUILayout.Button(array2[j], Array.Empty<GUILayoutOption>()))
					{
						selectedHostGroupIndex = j;
						hostGroupDropdownOpen = false;
					}
				}
				GUILayout.EndVertical();
			}
			GUILayout.Space(10f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Give Token", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				ReviveTokenManager.AddToken(array2[selectedHostGroupIndex]);
			}
			if (GUILayout.Button("Remove Token", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				ReviveTokenManager.RemoveToken(array2[selectedHostGroupIndex]);
			}
			GUILayout.EndHorizontal();
			GUILayout.EndScrollView();
		}

		private void TeleportToPlayer(Character target)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			Character localCharacter = GetLocalCharacter();
			if (!((Object)(object)localCharacter == (Object)null) && !((Object)(object)target == (Object)null))
			{
				Vector3 val = target.Center + Vector3.right * 2f;
				localCharacter.refs.view.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val, true });
			}
		}

		private void TeleportPlayerToMe(Character target)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			Character localCharacter = GetLocalCharacter();
			if (!((Object)(object)localCharacter == (Object)null) && !((Object)(object)target == (Object)null))
			{
				Vector3 val = localCharacter.Center + Vector3.right * 2f;
				target.refs.view.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val, true });
			}
		}

		private void TeleportPlayerToBiomeEnd(Character target)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			Vector3 currentBiomeEndPosition = Patch_Biome.CurrentBiomeEndPosition;
			if (!((Object)(object)target == (Object)null) && !(currentBiomeEndPosition == Vector3.zero))
			{
				target.refs.view.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2]
				{
					currentBiomeEndPosition + Vector3.right * 1.5f,
					true
				});
			}
		}

		private void RevivePlayer(Character target)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Expected I4, but got Unknown
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			Character localCharacter = GetLocalCharacter();
			if ((Object)(object)localCharacter == (Object)null || (Object)(object)target == (Object)null || ((Object)(object)target.data != (Object)null && !target.data.dead))
			{
				return;
			}
			Vector3 zero = Vector3.zero;
			int ownerActorNr = ((MonoBehaviourPun)target).photonView.OwnerActorNr;
			if (SkeletonTracker.TryGetSkeleton(ownerActorNr, out var skeleton))
			{
				zero = SkeletonTracker.GetSkeletonPosition(skeleton) + Vector3.up * 1f;
			}
			else
			{
				string groupOfPlayer = GroupManager.GetGroupOfPlayer(ownerActorNr);
				Character val = null;
				foreach (Character allPlayerCharacter in PlayerHandler.GetAllPlayerCharacters())
				{
					if (!((Object)(object)allPlayerCharacter == (Object)null) && !allPlayerCharacter.data.dead && !(GroupManager.GetGroupOfPlayer(((MonoBehaviourPun)allPlayerCharacter).photonView.OwnerActorNr) != groupOfPlayer))
					{
						val = allPlayerCharacter;
						break;
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					zero = ((Component)val.refs.movement).transform.position + Vector3.up * 1f;
				}
				else
				{
					zero = localCharacter.Center + Vector3.up * 1f;
					if (localCharacter.data.dead)
					{
						Character val2 = null;
						foreach (Character allPlayerCharacter2 in PlayerHandler.GetAllPlayerCharacters())
						{
							if ((Object)(object)allPlayerCharacter2 != (Object)null && !allPlayerCharacter2.data.dead)
							{
								val2 = allPlayerCharacter2;
								break;
							}
						}
						if ((Object)(object)val2 != (Object)null)
						{
							zero = ((Component)val2.refs.movement).transform.position + Vector3.up * 1f;
						}
					}
				}
			}
			((MonoBehaviourPun)target).photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3]
			{
				zero,
				true,
				(int)MapHandler.CurrentSegmentNumber
			});
			ReviveNetwork.InstanceView.RPC("RPC_SinnerPeak_DestroySkeleton", (RpcTarget)0, new object[1] { ownerActorNr });
		}

		private void ReviveAllPlayers()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected I4, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			RespawnChest val = Object.FindAnyObjectByType<RespawnChest>();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"[SinnerPeak] No RespawnChest found in scene.");
				return;
			}
			Vector3 val2 = ((Component)val).transform.position + ((Component)val).transform.up * 6f;
			int num = (int)val.SegmentNumber;
			Plugin.Log.LogInfo((object)"[SinnerPeak] Global Revive triggered.");
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if (!((Object)(object)allCharacter == (Object)null) && !((Object)(object)allCharacter.data == (Object)null) && (allCharacter.data.dead || allCharacter.data.fullyPassedOut))
				{
					Vector3 onUnitSphere = Random.onUnitSphere;
					Vector3 val3 = val2 + onUnitSphere;
					((MonoBehaviourPun)allCharacter).photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { val3, true, num });
				}
			}
		}

		private void DrawModdedPlayersTab()
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.Label("<b>Players</b>", headerLabel, Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
			{
				GUILayout.Label("Not in a room.", richLabel, Array.Empty<GUILayoutOption>());
				return;
			}
			EnsurePlayerCache();
			List<Character> list = cachedCharacters;
			if (list == null || list.Count == 0)
			{
				GUILayout.Label("No players found.", richLabel, Array.Empty<GUILayoutOption>());
				return;
			}
			GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
			scrollPlayers = GUILayout.BeginScrollView(scrollGroups, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
			foreach (Character cachedCharacter in cachedCharacters)
			{
				if (!((Object)(object)cachedCharacter == (Object)null) && !((Object)(object)((MonoBehaviourPun)cachedCharacter).photonView == (Object)null) && ((MonoBehaviourPun)cachedCharacter).photonView.Owner != null)
				{
					Player owner = ((MonoBehaviourPun)cachedCharacter).photonView.Owner;
					int actorNumber = owner.ActorNumber;
					string text = $"{owner.NickName} ({actorNumber})";
					string text2 = (ModdedClientRegistry.IsModded(actorNumber) ? "<color=green><b>MODDED</b></color>" : "<color=yellow><b>VANILLA</b></color>");
					GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Label(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(240f) });
					GUILayout.Label(text2, richLabel, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(100f) });
					GUILayout.EndHorizontal();
					CharacterData data = cachedCharacter.data;
					if ((Object)(object)data == (Object)null)
					{
						GUILayout.Label("Stamina: <i>loading...</i>", richLabel, Array.Empty<GUILayoutOption>());
						GUILayout.EndVertical();
						continue;
					}
					float stamina = Mathf.Clamp01(data.currentStamina);
					GUILayout.Label("Stamina:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
					DrawStaminaBar(stamina);
					GUILayout.EndVertical();
				}
			}
			GUILayout.Space(20f);
			GUILayout.EndScrollView();
			GUILayout.EndVertical();
		}

		private Character GetLocalCharacter()
		{
			if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
			{
				return null;
			}
			int actorNumber = PhotonNetwork.LocalPlayer.ActorNumber;
			Character result = default(Character);
			if (PlayerHandler.TryGetCharacter(actorNumber, ref result))
			{
				return result;
			}
			return null;
		}

		private void EnsureSkinStyles()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			if (skinButtonStyle == null)
			{
				skinButtonStyle = new GUIStyle(GUI.skin.button);
				skinButtonSelectedStyle = new GUIStyle(GUI.skin.button);
				Texture2D background = GUI.skin.button.hover.background;
				skinButtonSelectedStyle.normal.background = background;
				skinButtonSelectedStyle.hover.background = background;
				skinButtonSelectedStyle.active.background = background;
				skinButtonSelectedStyle.focused.background = background;
			}
		}

		private int SkinSelector(int currentIndex)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			EnsureSkinStyles();
			if ((Object)(object)Singleton<Customization>.Instance == (Object)null || Singleton<Customization>.Instance.skins == null || Singleton<Customization>.Instance.skins.Length == 0)
			{
				GUILayout.Label("Skins not loaded yet.", richLabel, Array.Empty<GUILayoutOption>());
				return currentIndex;
			}
			CustomizationOption[] skins = Singleton<Customization>.Instance.skins;
			int num = skins.Length;
			int num2 = 6;
			int num3 = Mathf.CeilToInt((float)num / (float)num2);
			int num4 = currentIndex;
			GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
			for (int i = 0; i < num3; i++)
			{
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				for (int j = 0; j < num2; j++)
				{
					int num5 = i * num2 + j;
					if (num5 >= num)
					{
						break;
					}
					Color color = skins[num5].color;
					GUI.color = color;
					GUIStyle val = ((num5 == num4) ? skinButtonSelectedStyle : skinButtonStyle);
					if (GUILayout.Button("", val, (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(25f),
						GUILayout.Height(25f)
					}))
					{
						num4 = num5;
					}
					GUI.color = Color.white;
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.EndVertical();
			return num4;
		}

		private Color GetSkinColor(int index)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return Singleton<Customization>.Instance.skins[index].color;
		}

		private void DrawGroupDropdown()
		{
			EnsureGroupCache();
			string[] array = cachedGroupNames;
			if (array.Length == 0)
			{
				GUILayout.Label("No groups created.", richLabel, Array.Empty<GUILayoutOption>());
				return;
			}
			if (selectedGroupIndex >= array.Length)
			{
				selectedGroupIndex = 0;
			}
			if (GUILayout.Button("Assign to: " + array[selectedGroupIndex], (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(25f) }))
			{
				dropdownOpen = !dropdownOpen;
			}
			if (!dropdownOpen)
			{
				return;
			}
			GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), Array.Empty<GUILayoutOption>());
			for (int i = 0; i < array.Length; i++)
			{
				if (GUILayout.Button(array[i], Array.Empty<GUILayoutOption>()))
				{
					selectedGroupIndex = i;
					dropdownOpen = false;
					autoScrollTargetIndex = i;
				}
			}
			GUILayout.EndVertical();
		}

		private string[] GetGroupNames()
		{
			EnsureGroupCache();
			return cachedGroupNames;
		}

		private string GetGroupNameByIndex(int index)
		{
			EnsureGroupCache();
			if (index < 0 || index >= cachedGroupNames.Length)
			{
				return "Ungrouped";
			}
			return cachedGroupNames[index];
		}

		private void ForceRefreshPlayerCache()
		{
			if (!PhotonNetwork.InRoom || PhotonNetwork.CurrentRoom == null)
			{
				cachedCharacters.Clear();
				cachedPlayerNames = Array.Empty<string>();
				nextPlayerCacheTime = Time.time + 3f;
				return;
			}
			cachedCharacters = PlayerHandler.GetAllPlayerCharacters() ?? new List<Character>();
			int count = cachedCharacters.Count;
			cachedPlayerNames = new string[count];
			for (int i = 0; i < count; i++)
			{
				Character val = cachedCharacters[i];
				if ((Object)(object)val == (Object)null || (Object)(object)((MonoBehaviourPun)val).photonView == (Object)null || ((MonoBehaviourPun)val).photonView.Owner == null)
				{
					cachedPlayerNames[i] = "Unknown";
					continue;
				}
				Player owner = ((MonoBehaviourPun)val).photonView.Owner;
				cachedPlayerNames[i] = owner.NickName + " (" + owner.ActorNumber + ")";
			}
			nextPlayerCacheTime = Time.time + 3f;
		}

		private void ForceRefreshGroupCache()
		{
			Dictionary<string, Group>.KeyCollection keys = GroupManager.Groups.Keys;
			cachedGroupNames = new string[keys.Count];
			int num = 0;
			foreach (string item in keys)
			{
				cachedGroupNames[num++] = item;
			}
			lastGroupCount = cachedGroupNames.Length;
			groupCacheInitialized = true;
		}

		private void DrawStaminaBar(float stamina, float width = 120f, float height = 14f)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = GUILayoutUtility.GetRect(width, height);
			GUI.color = Color.black;
			GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture);
			Color color = ((!(stamina > 0.5f)) ? Color.Lerp(Color.red, Color.yellow, stamina * 2f) : Color.Lerp(Color.yellow, Color.green, (stamina - 0.5f) * 2f));
			GUI.color = color;
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width * stamina, ((Rect)(ref rect)).height), (Texture)(object)Texture2D.whiteTexture);
			GUI.color = Color.white;
		}
	}
	public class LeaderboardUI : MonoBehaviour
	{
		private const float MIN_WIDTH = 300f;

		private const float MAX_WIDTH = 600f;

		private Rect windowRect = new Rect(50f, 50f, 450f, 600f);

		private GUIStyle windowStyle;

		private GUIStyle labelStyle;

		private GUIStyle titleStyle;

		private static readonly GUIContent tempContent = new GUIContent();

		private bool stylesReady;

		private float nextWidthRecalcTime;

		private float cachedContentWidth = 300f;

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Plugin.ToggleLeaderboardKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				Plugin.ShowLeaderboard.Value = !Plugin.ShowLeaderboard.Value;
			}
			value = Plugin.TogglePointsKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				Plugin.ShowPointsMode = !Plugin.ShowPointsMode;
			}
		}

		private void OnGUI()
		{
			//IL_0022: 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)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//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)
			if (Plugin.ShowLeaderboard.Value)
			{
				if (!stylesReady)
				{
					InitStyles();
				}
				windowRect = GUI.Window(69420, windowRect, Plugin.ShowPointsMode ? new WindowFunction(DrawPointsWindow) : new WindowFunction(DrawMainWindow), GUIContent.none, windowStyle);
			}
		}

		private void InitStyles()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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)
			//IL_004e: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			windowStyle = new GUIStyle(GUI.skin.window);
			windowStyle.normal.background = Texture2D.blackTexture;
			labelStyle = new GUIStyle(GUI.skin.label)
			{
				fontSize = 16,
				richText = true
			};
			titleStyle = new GUIStyle(GUI.skin.label)
			{
				fontSize = 20,
				richText = true,
				alignment = (TextAnchor)4
			};
			stylesReady = true;
		}

		private void DrawMainWindow(int id)
		{
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			GUILayout.Label("<b>SinnerPeak Leaderboard</b>", titleStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(20f);
			MountainProgressHandler instance = Singleton<MountainProgressHandler>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				GUILayout.Label("<i>Waiting for game...</i>", labelStyle, Array.Empty<GUILayoutOption>());
				GUI.DragWindow();
				return;
			}
			int maxProgressPointReached = instance.maxProgressPointReached;
			if (!Plugin.UseGroupLeaderboard.Value)
			{
				List<PlayerStats> sortedPlayers = Leaderboard.GetSortedPlayers();
				for (int i = 0; i < sortedPlayers.Count; i++)
				{
					PlayerStats playerStats = sortedPlayers[i];
					if (playerStats == null)
					{
						continue;
					}
					int actorNumber = playerStats.ActorNumber;
					if (GroupManager.IsSpectator(actorNumber))
					{
						continue;
					}
					string text = ColorUtility.ToHtmlStringRGB(playerStats.Color);
					string text2;
					if (playerStats.DNF)
					{
						text2 = "<color=#888888>" + playerStats.Name + "</color> — " + playerStats.Height.ToString("F1") + "m <color=#FF2222><b>DNF</b></color>";
					}
					else
					{
						string text3 = "<color=#" + text + ">" + playerStats.Name + "</color>";
						text2 = text3 + " — " + playerStats.Height.ToString("F1") + "m";
						if (playerStats.LastFinishedBiome == maxProgressPointReached)
						{
							text2 += " <color=#00FF00><b>FINISHED</b></color>";
						}
					}
					GUILayout.Label(text2, labelStyle, Array.Empty<GUILayoutOption>());
					tempContent.text = text2;
					float num2 = labelStyle.CalcSize(tempContent).x + 40f;
					if (num2 > num)
					{
						num = num2;
					}
				}
			}
			else
			{
				List<Leaderboard.GroupStats> groupedLeaderboard = Leaderboard.GetGroupedLeaderboard();
				for (int j = 0; j < groupedLeaderboard.Count; j++)
				{
					Leaderboard.GroupStats groupStats = groupedLeaderboard[j];
					if (GroupManager.IsSpectatorGroup(groupStats.GroupName))
					{
						continue;
					}
					string text4 = ColorUtility.ToHtmlStringRGB(groupStats.Color);
					bool flag = Leaderboard.HasGroupFinished(groupStats.GroupName, maxProgressPointReached);
					bool flag2 = Leaderboard.HasGroupDNF(groupStats.GroupName);
					int tokens = ReviveTokenManager.GetTokens(groupStats.GroupName);
					string text5 = "<b><color=#" + text4 + ">" + groupStats.GroupName + $" ({tokens})</color></b> — Avg: " + groupStats.AverageHeight.ToString("F1") + "m";
					if (flag)
					{
						text5 += " <color=#00FF00><b>FINISHED</b></color>";
					}
					else if (flag2)
					{
						text5 += " <color=#FF2222><b>DNF</b></color>";
					}
					GUILayout.Label(text5, labelStyle, Array.Empty<GUILayoutOption>());
					tempContent.text = text5;
					float num3 = labelStyle.CalcSize(tempContent).x + 40f;
					if (num3 > num)
					{
						num = num3;
					}
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Space(20f);
					GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
					List<PlayerStats> members = groupStats.Members;
					for (int k = 0; k < members.Count; k++)
					{
						PlayerStats playerStats2 = members[k];
						if (GroupManager.IsSpectator(playerStats2.ActorNumber))
						{
							continue;
						}
						string text6 = ColorUtility.ToHtmlStringRGB(playerStats2.Color);
						string text7;
						if (playerStats2.DNF)
						{
							text7 = "<color=#888888>" + playerStats2.Name + "</color> — " + playerStats2.Height.ToString("F1") + "m <color=#FF2222><b>DNF</b></color>";
						}
						else
						{
							string text8 = "<color=#" + text6 + ">" + playerStats2.Name + "</color>";
							text7 = text8 + " — " + playerStats2.Height.ToString("F1") + "m";
							if (playerStats2.LastFinishedBiome == maxProgressPointReached)
							{
								text7 += " <color=#00FF00><b>FINISHED</b></color>";
							}
						}
						GUILayout.Label(text7, labelStyle, Array.Empty<GUILayoutOption>());
					}
					GUILayout.EndVertical();
					GUILayout.EndHorizontal();
					GUILayout.Space(8f);
				}
			}
			if (Time.time >= nextWidthRecalcTime)
			{
				cachedContentWidth = Mathf.Clamp(num, 300f, 600f);
				nextWidthRecalcTime = Time.time + 2f;
			}
			((Rect)(ref windowRect)).width = cachedContentWidth;
			GUI.DragWindow();
		}

		private void DrawPointsWindow(int id)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.Label("<b>Total Points</b>", titleStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(20f);
			List<PlayerStats> sortedPlayersByPoints = Leaderboard.GetSortedPlayersByPoints();
			for (int i = 0; i < sortedPlayersByPoints.Count; i++)
			{
				PlayerStats playerStats = sortedPlayersByPoints[i];
				if (!GroupManager.IsSpectator(playerStats.ActorNumber))
				{
					int actorNumber = playerStats.ActorNumber;
					int value;
					int num = (Plugin.TotalPoints.TryGetValue(actorNumber, out value) ? value : 0);
					string text = ColorUtility.ToHtmlStringRGB(playerStats.Color);
					string text2 = "<color=#" + text + ">" + playerStats.Name + "</color> — <color=#FFD700>" + num + " pts</color>";
					GUILayout.Label(text2, labelStyle, Array.Empty<GUILayoutOption>());
				}
			}
			GUI.DragWindow();
		}
	}
}
namespace SinnerPeak.Revive
{
	public class ReviveBootstrap : MonoBehaviourPunCallbacks
	{
		private const int STATIC_REVIVE_VIEW_ID = 2147000000;

		private static ReviveBootstrap _instance;

		private void Awake()
		{
			if ((Object)(object)_instance != (Object)null && (Object)(object)_instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			_instance = this;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			if ((Object)(object)((Component)this).GetComponent<ReviveTokenSync>() == (Object)null)
			{
				((Component)this).gameObject.AddComponent<ReviveTokenSync>();
			}
		}

		public override void OnJoinedRoom()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
			{
				if ((Object)(object)ReviveNetwork.InstanceView == (Object)null)
				{
					GameObject val = new GameObject("SinnerPeak_ReviveNetwork");
					PhotonView val2 = val.AddComponent<PhotonView>();
					val2.ViewID = 2147000000;
					val.AddComponent<ReviveNetwork>();
					Object.DontDestroyOnLoad((Object)(object)val);
				}
				if ((Object)(object)ReviveHostRuntime.Instance == (Object)null)
				{
					GameObject val3 = new GameObject("SinnerPeak_ReviveHostRuntime");
					val3.AddComponent<ReviveHostRuntime>();
					Object.DontDestroyOnLoad((Object)(object)val3);
				}
			}
		}

		public override void OnLeftRoom()
		{
			if ((Object)(object)ReviveNetwork.InstanceView != (Object)null)
			{
				GameObject gameObject = ((Component)ReviveNetwork.InstanceView).gameObject;
				Object.Destroy((Object)(object)gameObject);
				ReviveNetwork.InstanceView = null;
			}
			if ((Object)(object)ReviveHostRuntime.Instance != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)ReviveHostRuntime.Instance).gameObject);
			}
		}
	}
	public static class ReviveConfig
	{
		public const float ReviveHoldSeconds = 3f;

		public const float CrouchReviveSeconds = 3f;

		public static float ReviveRadius => Plugin.ReviveRadius.Value;

		public static float ReviveRadiusSqr => ReviveRadius * ReviveRadius;

		public static int MaxTokens => Plugin.MaxTokens.Value;

		public static int StartTokens => Plugin.StartTokens.Value;

		public static KeyCode ReviveKey
		{
			get
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				KeyboardShortcut value = Plugin.ReviveKey.Value;
				return ((KeyboardShortcut)(ref value)).MainKey;
			}
		}
	}
	public static class ReviveTokenManager
	{
		public static readonly Dictionary<string, int> TokenCache = new Dictionary<string, int>();

		private static string Key(string groupName)
		{
			return "reviveTokens_" + groupName;
		}

		public static int GetTokens(string groupName)
		{
			if (string.IsNullOrWhiteSpace(groupName))
			{
				return 0;
			}
			if (TokenCache.TryGetValue(groupName, out var value))
			{
				return value;
			}
			if (PhotonNetwork.CurrentRoom != null && ((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)Key(groupName), out object value2) && value2 is int num)
			{
				TokenCache[groupName] = num;
				return num;
			}
			TokenCache[groupName] = 0;
			return 0;
		}

		private static void SetTokens(string groupName, int tokens)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			if (PhotonNetwork.IsMasterClient)
			{
				tokens = Mathf.Clamp(tokens, 0, ReviveConfig.MaxTokens);
				Hashtable val = new Hashtable { [(object)Key(groupName)] = tokens };
				PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
				TokenCache[groupName] = tokens;
			}
		}

		public static void AddToken(string groupName, int amount = 1)
		{
			SetTokens(groupName, GetTokens(groupName) + amount);
		}

		public static void RemoveToken(string groupName, int amount = 1)
		{
			SetTokens(groupName, Mathf.Max(0, GetTokens(groupName) - amount));
		}

		public static bool TrySpendToken(string groupName)
		{
			int tokens = GetTokens(groupName);
			if (tokens <= 0)
			{
				return false;
			}
			SetTokens(groupName, tokens - 1);
			return true;
		}

		public static void EnsureGroupTokenExists(string groupName)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (PhotonNetwork.IsMasterClient)
			{
				string text = Key(groupName);
				if (!((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).ContainsKey((object)text))
				{
					Hashtable val = new Hashtable { [(object)text] = ReviveConfig.StartTokens };
					PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
					TokenCache[groupName] = ReviveConfig.StartTokens;
				}
			}
		}

		public static void DeleteGroupToken(string groupName)
		{
			//IL_0021: 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_0031: Expected O, but got Unknown
			if (PhotonNetwork.IsMasterClient)
			{
				string text = Key(groupName);
				if (((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).ContainsKey((object)text))
				{
					Hashtable val = new Hashtable { [(object)text] = null };
					PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
				}
				TokenCache.Remove(groupName);
			}
		}
	}
	public static class SkeletonTracker
	{
		private static readonly Dictionary<int, GameObject> _skeletonByActor = new Dictionary<int, GameObject>(16);

		public static IEnumerable<KeyValuePair<int, GameObject>> AllSkeletons => _skeletonByActor;

		public static Vector3 GetSkeletonPosition(GameObject skeleton)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)skeleton == (Object)null)
			{
				return Vector3.zero;
			}
			Skelleton component = skeleton.GetComponent<Skelleton>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.hip != (Object)null)
			{
				return component.hip.position;
			}
			return skeleton.transform.position;
		}

		public static void RegisterSkeleton(int actorNumber, GameObject skeleton)
		{
			if ((Object)(object)skeleton != (Object)null)
			{
				_skeletonByActor[actorNumber] = skeleton;
			}
		}

		public static void UnregisterSkeleton(int actorNumber)
		{
			_skeletonByActor.Remove(actorNumber);
		}

		public static bool TryGetSkeleton(int actor, out GameObject skeleton)
		{
			return _skeletonByActor.TryGetValue(actor, out skeleton);
		}
	}
	[HarmonyPatch(typeof(Skelleton), "SpawnSkelly")]
	public static class Patch_Skelleton_SpawnSkelly
	{
		private static void Postfix(Skelleton __instance, Character __0)
		{
			int ownerActorNr = ((MonoBehaviourPun)__0).photonView.OwnerActorNr;
			SkeletonTracker.RegisterSkeleton(ownerActorNr, ((Component)__instance).gameObject);
		}
	}
	[HarmonyPatch(typeof(Character), "RPCA_ReviveAtPosition")]
	public static class Patch_Character_ReviveCleanup
	{
		private static void Postfix(Character __instance)
		{
			if (!((Object)(object)((__instance != null) ? ((MonoBehaviourPun)__instance).photonView : null) == (Object)null))
			{
				SkeletonTracker.UnregisterSkeleton(((MonoBehaviourPun)__instance).photonView.OwnerActorNr);
			}
		}
	}
	public static class PhotonUtil
	{
		public static string GetNick(int actorNumber)
		{
			if (PhotonNetwork.CurrentRoom == null)
			{
				return $"Player {actorNumber}";
			}
			if (PhotonNetwork.CurrentRoom.Players.TryGetValue(actorNumber, out var value))
			{
				if (!string.IsNullOrWhiteSpace(value.NickName))
				{
					return value.NickName;
				}
				return $"Player {actorNumber}";
			}
			return $"Player {actorNumber}";
		}
	}
	public static class ReviveManager
	{
		private static readonly Dictionary<int, float> _crouchTimers = new Dictionary<int, float>(16);

		public static void ResetCrouchTimer(int actor)
		{
			_crouchTimers[actor] = 0f;
		}

		public static void AddCrouchTime(int actor, float dt)
		{
			if (!_crouchTimers.ContainsKey(actor))
			{
				_crouchTimers[actor] = 0f;
			}
			_crouchTimers[actor] += dt;
		}

		public static float GetCrouchTime(int actor)
		{
			if (!_crouchTimers.TryGetValue(actor, out var value))
			{
				return 0f;
			}
			return value;
		}

		public static void TryReviveFromHost(int reviverActor)
		{
			//IL_003c: 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_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.IsMasterClient)
			{
				return;
			}
			Character val = FindCharacter(reviverActor);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			string groupOfPlayer = GroupManager.GetGroupOfPlayer(reviverActor);
			if (string.IsNullOrEmpty(groupOfPlayer) || GroupManager.IsSpectatorGroup(groupOfPlayer) || ReviveTokenManager.GetTokens(groupOfPlayer) <= 0)
			{
				return;
			}
			Vector3 center = val.Center;
			int num = -1;
			float num2 = float.MaxValue;
			foreach (KeyValuePair<int, GameObject> allSkeleton in SkeletonTracker.AllSkeletons)
			{
				int key = allSkeleton.Key;
				GameObject value = allSkeleton.Value;
				if (!((Object)(object)value == (Object)null) && !(GroupManager.GetGroupOfPlayer(key) != groupOfPlayer))
				{
					Vector3 val2 = center - SkeletonTracker.GetSkeletonPosition(value);
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (sqrMagnitude < num2 && sqrMagnitude <= ReviveConfig.ReviveRadiusSqr)
					{
						num2 = sqrMagnitude;
						num = key;
					}
				}
			}
			if (num == -1 || !ReviveTokenManager.TrySpendToken(groupOfPlayer))
			{
				return;
			}
			Character val3 = FindCharacter(num);
			if ((Object)(object)val3 != (Object)null)
			{
				string characterName = val.characterName;
				string characterName2 = val3.characterName;
				int num3 = ((!((Object)(object)Singleton<MapHandler>.Instance != (Object)null)) ? (-1) : ((int)MapHandler.CurrentSegmentNumber));
				((MonoBehaviourPun)val3).photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { center, true, num3 });
				Leaderboard.ClearDNF(val3);
				if (SkeletonTracker.TryGetSkeleton(num, out var skeleton))
				{
					Object.Destroy((Object)(object)skeleton);
					SkeletonTracker.UnregisterSkeleton(num);
				}
				string message = "[Revive] Revive complete: " + characterName2 + " revived by " + characterName;
				Webhook.Send(message);
			}
		}

		private static Character FindCharacter(int actor)
		{
			List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
			for (int i = 0; i < allPlayerCharacters.Count; i++)
			{
				Character val = allPlayerCharacters[i];
				if ((Object)(object)val != (Object)null && ((MonoBehaviourPun)val).photonView.OwnerActorNr == actor)
				{
					return val;
				}
			}
			return null;
		}
	}
	public class ReviveHostRuntime : MonoBehaviour
	{
		private const float TICK_RATE = 0.25f;

		private float _nextTick;

		private readonly List<Character> _cachedPlayers = new List<Character>(16);

		private readonly List<KeyValuePair<int, GameObject>> _cachedSkeletons = new List<KeyValuePair<int, GameObject>>(16);

		private readonly Dictionary<int, string> _groupCache = new Dictionary<int, string>(16);

		public static ReviveHostRuntime Instance { get; private set; }

		private void Awake()
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			Instance = this;
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			GroupManager.OnPlayerGroupChanged += HandleGroupChanged;
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				GroupManager.OnPlayerGroupChanged -= HandleGroupChanged;
				Instance = null;
			}
		}

		private void HandleGroupChanged(int actor, string newGroup)
		{
			_groupCache.Clear();
		}

		private void Update()
		{
			if (PhotonNetwork.IsMasterClient && !(Time.time < _nextTick))
			{
				_nextTick = Time.time + 0.25f;
				RefreshPlayers();
				RefreshSkeletons();
				if (_cachedSkeletons.Count != 0)
				{
					RunReviveScan();
				}
			}
		}

		private void RefreshPlayers()
		{
			_cachedPlayers.Clear();
			List<Character> allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters();
			for (int i = 0; i < allPlayerCharacters.Count; i++)
			{
				_cachedPlayers.Add(allPlayerCharacters[i]);
			}
		}

		private void RefreshSkeletons()
		{
			_cachedSkeletons.Clear();
			foreach (KeyValuePair<int, GameObject> allSkeleton in SkeletonTracker.AllSkeletons)
			{
				_cachedSkeletons.Add(allSkeleton);
			}
		}

		private string GetGroupCached(int actor)
		{
			if (_groupCache.TryGetValue(actor, out var value))
			{
				return value;
			}
			value = GroupManager.GetGroupOfPlayer(actor);
			_groupCache[actor] = value;
			return value;
		}

		public void ClearGroupCache()
		{
			_groupCache.Clear();
		}

		private void RunReviveScan()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < _cachedSkeletons.Count; i++)
			{
				KeyValuePair<int, GameObject> keyValuePair = _cachedSkeletons[i];
				int key = keyValuePair.Key;
				GameObject skeleton = keyValuePair.Value;
				if ((Object)(object)skeleton == (Object)null && (!SkeletonTracker.TryGetSkeleton(key, out skeleton) || (Object)(object)skeleton == (Object)null))
				{
					continue;
				}
				string groupCached = GetGroupCached(key);
				if (string.IsNullOrEmpty(groupCached) || GroupManager.IsSpectatorGroup(groupCached) || ReviveTokenManager.GetTokens(groupCached) <= 0)
				{
					continue;
				}
				Vector3 skeletonPosition = SkeletonTracker.GetSkeletonPosition(skeleton);
				for (int j = 0; j < _cachedPlayers.Count; j++)
				{
					Character val = _cachedPlayers[j];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					CharacterData data = val.data;
					if (data.dead || data.fullyPassedOut)
					{
						continue;
					}
					int ownerActorNr = ((MonoBehaviourPun)val).photonView.OwnerActorNr;
					if (GetGroupCached(ownerActorNr) != groupCached)
					{
						continue;
					}
					Vector3 center = val.Center;
					Vector3 val2 = center - skeletonPosition;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (sqrMagnitude > ReviveConfig.ReviveRadiusSqr)
					{
						ReviveManager.ResetCrouchTimer(ownerActorNr);
						continue;
					}
					if (!data.isCrouching)
					{
						ReviveManager.ResetCrouchTimer(ownerActorNr);
						continue;
					}
					ReviveManager.AddCrouchTime(ownerActorNr, 0.25f);
					float crouchTime = ReviveManager.GetCrouchTime(ownerActorNr);
					if (crouchTime >= 3f)
					{
						Plugin.Log.LogInfo((object)("[Revive] " + val.characterName + ": CROUCH REVIVE TRIGGERED"));
						ReviveManager.ResetCrouchTimer(ownerActorNr);
						ReviveManager.TryReviveFromHost(ownerActorNr);
					}
				}
			}
		}
	}
	public class ReviveNetwork : MonoBehaviourPun
	{
		public static PhotonView InstanceView;

		private void Awake()
		{
			InstanceView = ((Component)this).GetComponent<PhotonView>();
		}

		[PunRPC]
		public void RPC_SinnerPeak_RequestRevive(int reviverActor)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				ReviveManager.TryReviveFromHost(reviverActor);
			}
		}

		[PunRPC]
		public void RPC_SinnerPeak_ShowRevivePrompt(string msg)
		{
			if (!((Object)(object)GUIManager.instance == (Object)null))
			{
				((TMP_Text)GUIManager.instance.interactPromptText).text = msg;
				if (!string.IsNullOrEmpty(msg))
				{
					GUIManager.instance.interactName.SetActive(true);
					GUIManager.instance.interactPromptPrimary.SetActive(false);
					GUIManager.instance.interactPromptSecondary.SetActive(false);
					GUIManager.instance.interactPromptHold.SetActive(false);
				}
			}
		}
	}
	public class ReviveRuntime : MonoBehaviour
	{
		private bool _isHolding;

		private float _holdTime;

		private bool _reviveAvailable;

		private string _tokenMessage = "";

		private float _tokenMessageTimer;

		private Texture2D _progressTex;

		private GUIStyle _tokenStyle;

		private GUIStyle _promptStyle;

		private GUIStyle _barBgStyle;

		private GUIStyle _barFgStyle;

		private Rect _tokenRect;

		private Rect _promptRect;

		private Rect _barBgRect;

		private Rect _barFgRectBase;

		private Texture2D _uiBgTex;

		private void Start()
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			_uiBgTex = new Texture2D(1, 1);
			_uiBgTex.SetPixel(0, 0, new Color(0f, 0f, 0f, 0.4f));
			_uiBgTex.Apply();
			_tokenStyle = new GUIStyle
			{
				fontSize = 22,
				alignment = (TextAnchor)4
			};
			_tokenStyle.normal.textColor = Color.yellow;
			_tokenStyle.normal.background = _uiBgTex;
			_promptStyle = new GUIStyle
			{
				fontSize = 20,
				alignment = (TextAnchor)4
			};
			_promptStyle.normal.textColor = Color.cyan;
			_promptStyle.normal.background = _uiBgTex;
			_barBgStyle = new GUIStyle();
			_barBgStyle.normal.background = Texture2D.blackTexture;
			_barFgStyle = new GUIStyle();
			_tokenRect = new Rect((float)Screen.width / 2f - 200f, 40f, 400f, 40f);
			_promptRect = new Rect((float)Screen.width / 2f - 150f, (float)Screen.height - 120f, 300f, 40f);
			float num = 300f;
			float num2 = 25f;
			float num3 = (float)Screen.width / 2f - num / 2f;
			float num4 = (float)Screen.height - 80f;
			_barBgRect = new Rect(num3, num4, num, num2);
			_barFgRectBase = new Rect(num3, num4, num, num2);
		}

		private void Update()
		{
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null || (Object)(object)((MonoBehaviourPun)localCharacter).photonView == (Object)null || !((MonoBehaviourPun)localCharacter).photonView.IsMine)
			{
				return;
			}
			if (Input.GetKeyDown((KeyCode)116))
			{
				int ownerActorNr = ((MonoBehaviourPun)localCharacter).photonView.OwnerActorNr;
				string groupOfPlayer = GroupManager.GetGroupOfPlayer(ownerActorNr);
				if (string.IsNullOrWhiteSpace(groupOfPlayer) || GroupManager.IsSpectatorGroup(groupOfPlayer))
				{
					_tokenMessage = "You are not in a revive‑eligible group.";
					_tokenMessageTimer = 3f;
				}
				else
				{
					int tokens = ReviveTokenManager.GetTokens(groupOfPlayer);
					_tokenMessage = $"Group {groupOfPlayer} has {tokens} revive token(s).";
					_tokenMessageTimer = 3f;
				}
			}
			if (_tokenMessageTimer > 0f)
			{
				_tokenMessageTimer -= Time.deltaTime;
			}
			if (localCharacter.data.dead || localCharacter.data.fullyPassedOut)
			{
				return;
			}
			_reviveAvailable = false;
			int ownerActorNr2 = ((MonoBehaviourPun)localCharacter).photonView.OwnerActorNr;
			string groupOfPlayer2 = GroupManager.GetGroupOfPlayer(ownerActorNr2);
			Vector3 center = localCharacter.Center;
			if (!string.IsNullOrEmpty(groupOfPlayer2) && !GroupManager.IsSpectatorGroup(groupOfPlayer2))
			{
				foreach (KeyValuePair<int, GameObject> allSkeleton in SkeletonTracker.AllSkeletons)
				{
					GameObject value = allSkeleton.Value;
					if (!((Object)(object)value == (Object)null) && !(GroupManager.GetGroupOfPlayer(allSkeleton.Key) != groupOfPlayer2))
					{
						Vector3 skeletonPosition = SkeletonTracker.GetSkeletonPosition(value);
						Vector3 val = center - skeletonPosition;
						float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
						if (sqrMagnitude <= ReviveConfig.ReviveRadiusSqr)
						{
							_reviveAvailable = true;
							break;
						}
					}
				}
			}
			if (Input.GetKeyDown(ReviveConfig.ReviveKey))
			{
				if (!HasReviveTokens(groupOfPlayer2))
				{
					_tokenMessage = "Your group has no revive tokens.";
					_tokenMessageTimer = 2f;
					return;
				}
				_isHolding = true;
				_holdTime = 0f;
			}
			if (Input.GetKeyUp(ReviveConfig.ReviveKey))
			{
				_isHolding = false;
				_holdTime = 0f;
			}
			if (_isHolding)
			{
				_holdTime += Time.deltaTime;
				if (_holdTime >= 3f)
				{
					_isHolding = false;
					_holdTime = 0f;
					ReviveNetwork.InstanceView.RPC("RPC_SinnerPeak_RequestRevive", (RpcTarget)2, new object[1] { ownerActorNr2 });
				}
			}
		}

		private bool HasReviveTokens(string group)
		{
			if (string.IsNullOrWhiteSpace(group))
			{
				return false;
			}
			return ReviveTokenManager.GetTokens(group) > 0;
		}

		private void OnGUI()
		{
			DrawTokenMessage();
			DrawRevivePrompt();
			DrawReviveProgress();
		}

		private void DrawTokenMessage()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (!(_tokenMessageTimer <= 0f))
			{
				GUI.Label(_tokenRect, _tokenMessage, _tokenStyle);
			}
		}

		private void DrawRevivePrompt()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (_reviveAvailable && !_isHolding)
			{
				GUI.Label(_promptRect, "Hold F to revive teammate", _promptStyle);
			}
		}

		private void DrawReviveProgress()
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if (!_isHolding)
			{
				return;
			}
			Character localCharacter = Character.localCharacter;
			if ((Object)(object)localCharacter == (Object)null || (Object)(object)((MonoBehaviourPun)localCharacter).photonView == (Object)null)
			{
				return;
			}
			string groupOfPlayer = GroupManager.GetGroupOfPlayer(((MonoBehaviourPun)localCharacter).photonView.OwnerActorNr);
			if (HasReviveTokens(groupOfPlayer))
			{
				float num = Mathf.Clamp01(_holdTime / 3f);
				if ((Object)(object)_progressTex == (Object)null)
				{
					_progressTex = new Texture2D(1, 1);
					_progressTex.SetPixel(0, 0, Color.green);
					_progressTex.Apply();
					_barFgStyle.normal.background = _progressTex;
				}
				GUI.Box(_barBgRect, GUIContent.none, _barBgStyle);
				Rect barFgRectBase = _barFgRectBase;
				((Rect)(ref barFgRectBase)).width = ((Rect)(ref barFgRectBase)).width * num;
				GUI.Box(barFgRectBase, GUIContent.none, _barFgStyle);
			}
		}
	}
	public class ReviveTokenSync : MonoBehaviourPunCallbacks
	{
		public override void OnRoomPropertiesUpdate(Hashtable changedProps)
		{
			foreach (object key2 in ((Dictionary<object, object>)(object)changedProps).Keys)
			{
				if (key2 is string text && text.StartsWith("reviveTokens_"))
				{
					string key = text.Substring("reviveTokens_".Length);
					if (changedProps[(object)text] is int value)
					{
						ReviveTokenManager.TokenCache[key] = value;
					}
					else
					{
						ReviveTokenManager.TokenCache.Remove(key);
					}
				}
			}
		}
	}
}
namespace SinnerPeak.Patches
{
	[HarmonyPatch(typeof(MapHandler), "InitializeMap")]
	public static class Patch_MapInitialize
	{
		private static void Postfix()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected I4, but got Unknown
			Patch_Biome.TryRegisterCampfireForSegment((int)MapHandler.CurrentSegmentNumber);
		}
	}
	[HarmonyPatch(typeof(MapHandler), "GoToSegment")]
	public static class Patch_MapGoToSegment
	{
		private static void Postfix(Segment s)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected I4, but got Unknown
			Patch_Biome.TryRegisterCampfireForSegment((int)s);
		}
	}
	public static class Patch_Biome
	{
		[HarmonyPatch(typeof(GUIManager), "SetHeroTitle")]
		public static class Patch_SetHeroTitle
		{
			[HarmonyPostfix]
			public static void AfterSetHeroTitle(string text)
			{
				Plugin.CurrentBiomeName = text;
			}
		}

		internal static Transform nextEndPoint;

		internal static int currentSegment = -1;

		internal static readonly HashSet<int> playersCompletedBiome = new HashSet<int>();

		private const float CAMPFIRE_H = 9f;

		private const float CAMPFIRE_V = 6f;

		private const float SUMMIT_H = 15f;

		private const float SUMMIT_V = 10f;

		private static Vector3 cachedCampfirePos;

		private static Vector3 cachedSummitPos;

		public static Vector3 CurrentBiomeEndPosition => cachedCampfirePos;

		public static void TryRegisterCampfireForSegment(int seg)
		{
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			if ((byte)seg == 4)
			{
				RegisterSummitAsCampfire();
				return;
			}
			int num = (((byte)seg == 5) ? (seg - 1) : seg);
			GameObject campfireRoot = MapHandler.GetCampfireRoot(num);
			if (!((Object)(object)campfireRoot == (Object)null))
			{
				Campfire componentInChildren = campfireRoot.GetComponentInChildren<Campfire>(true);
				if (!((Object)(object)componentInChildren == (Object)null))
				{
					RegisterCampfire(num, componentInChildren);
				}
			}
		}

		public static void RegisterCampfire(int segmentIndex, Campfire campfire)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			currentSegment = segmentIndex;
			nextEndPoint = ((Component)campfire).transform;
			cachedCampfirePos = campfire.Center();
			Leaderboard.AwardReviveTokensToNonPlacedGroups();
			Leaderboard.ResetBiomeFinishFlags();
			playersCompletedBiome.Clear();
		}

		private static void RegisterSummitAsCampfire()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected I4, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			MountainProgressHandler instance = Singleton<MountainProgressHandler>.Instance;
			if (!((Object)(object)instance == (Object)null) && instance.progressPoints != null && instance.progressPoints.Length != 0)
			{
				ProgressPoint val = instance.progressPoints[instance.progressPoints.Length - 1];
				if (!((Object)(object)val?.transform == (Object)null))
				{
					currentSegment = (int)MapHandler.CurrentSegmentNumber;
					nextEndPoint = val.transform;
					cachedCampfirePos = val.transform.position;
					Leaderboard.AwardReviveTokensToNonPlacedGroups();
					Leaderboard.ResetBiomeFinishFlags();
					playersCompletedBiome.Clear();
				}
			}
		}

		public static void UpdateCampfireCheck()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)nextEndPoint == (Object)null || currentSegment < 0)
			{
				return;
			}
			MountainProgressHandler instance = Singleton<MountainProgressHandler>.Instance;
			if (instance?.progressPoints != null && instance.progressPoints.Length != 0)
			{
				ProgressPoint val = instance.progressPoints[instance.progressPoints.Length - 1];
				cachedSummitPos = val.transform.position;
			}
			foreach (Character allPlayerCharacter in PlayerHandler.GetAllPlayerCharacters())
			{
				if ((Object)(object)allPlayerCharacter == (Object)null)
				{
					continue;
				}
				PlayerStats stats = Leaderboard.GetStats(allPlayerCharacter);
				if (stats.DNF)
				{
					continue;
				}
				int ownerActorNr = ((MonoBehaviourPun)allPlayerCharacter).photonView.OwnerActorNr;
				if (!GroupManager.IsSpectator(ownerActorNr) && !playersCompletedBiome.Contains(ownerActorNr))
				{
					Vector3 center = allPlayerCharacter.Center;
					float num = center.x - cachedCampfirePos.x;
					float num2 = center.z - cachedCampfirePos.z;
					bool flag = num * num + num2 * num2 < 81f && Mathf.Abs(center.y - cachedCampfirePos.y) < 6f;
					num = center.x - cachedSummitPos.x;
					num2 = center.z - cachedSummitPos.z;
					bool flag2 = currentSegment == 4 && num * num + num2 * num2 < 225f && Mathf.Abs(center.y - cachedSummitPos.y) < 10f;
					if (flag || flag2)
					{
						playersCompletedBiome.Add(ownerActorNr);
						Leaderboard.MarkBiomeFinished(allPlayerCharacter, currentSegment);
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(CharacterCustomization), "OnPlayerDataChange")]
	public static class Patch_CharacterCustomization_ApplyGroupSkin
	{
		private static void Prefix(CharacterCustomization __instance, PersistentPlayerData playerData)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null || playerData == null || !Object.op_Implicit((Object)(object)__instance) || (Object)(object)((Component)__instance).gameObject == (Object)null)
				{
					return;
				}
				PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
				if ((Object)(object)component == (Object)null)
				{
					return;
				}
				int ownerActorNr = component.OwnerActorNr;
				if (SkinSync.SkinCache.ForcedSkin.TryGetValue(ownerActorNr, out var value))
				{
					if (value >= Singleton<Customization>.Instance.skins.Length)
					{
						value = 0;
					}
					playerData.customizationData.currentSkin = value;
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)$"[Patch] Forcing skin {value} for actor {ownerActorNr}");
					}
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"[Patch] ApplyGroupSkin failed: {arg}");
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Start")]
	public static class Patch_CharacterStart
	{
		private static void Postfix(Character __instance)
		{
			if (__instance.IsPlayerControlled)
			{
				Leaderboard.GetStats(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Update")]
	public static class Patch_CharacterUpdate
	{
		private static void Postfix(Character __instance)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && __instance.refs != null && !((Object)(object)((MonoBehaviourPun)__instance).photonView == (Object)null) && ((MonoBehaviourPun)__instance).photonView.Owner != null && __instance.IsPlayerControlled)
			{
				float y = __instance.Center.y;
				Leaderboard.UpdatePlayer(__instance, y);
				MountainProgressHandler instance = Singleton<MountainProgressHandler>.Instance;
				_ = (Object)(object)instance == (Object)null;
			}
		}
	}
	[HarmonyPatch]
	public static class Patch_DeathRevive
	{
		[HarmonyPatch(typeof(RespawnChest), "RespawnAllPlayersHere")]
		[HarmonyPrefix]
		private static bool BlockChestRevive()
		{
			return false;
		}

		private static void Mark(Character c)
		{
			if ((Object)(object)c != (Object)null)
			{
				Leaderboard.MarkDNF(c);
			}
		}

		[HarmonyPatch(typeof(Character), "Die")]
		[HarmonyPostfix]
		private static void OnDie(Character __instance)
		{
			Mark(__instance);
		}

		[HarmonyPatch(typeof(Character), "RPCA_Die")]
		[HarmonyPostfix]
		private static void OnDieRPC(Character __instance)
		{
			Mark(__instance);
		}

		[HarmonyPatch(typeof(Character), "DieInstantly")]
		[HarmonyPostfix]
		private static void OnDieInstant(Character __instance)
		{
			Mark(__instance);
		}

		[HarmonyPatch(typeof(Character), "RPCA_SetDead")]
		[HarmonyPostfix]
		private static void OnSetDead(Character __instance)
		{
			Mark(__instance);
		}
	}
	public static class Patch_SpectatorModule
	{
		[HarmonyPatch(typeof(Character), "UpdateVariablesFixed")]
		public static class Patch_InfiniteStamina
		{
			private static void Postfix(Character __instance)
			{
				if (IsSpectator(__instance))
				{
					SpectatorImmunityManager.MaintainImmunity(__instance);
				}
				else
				{
					SpectatorImmunityManager.RemoveImmunity(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Character), "OutOfStamina")]
		public static class Patch_AlwaysHasStamina
		{
			private static bool Prefix(Character __instance, ref bool __result)
			{
				if (IsSpectator(__instance))
				{
					__result = false;
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(Character), "HandlePassedOut")]
		public static class Patch_NoPassOut
		{
			private static bool Prefix(Character __instance)
			{
				if (IsSpectator(__instance))
				{
					SpectatorImmunityManager.ApplyDeathImmunity(__instance);
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(Character), "HandleDeath")]
		public static class Patch_NoDeathTimer
		{
			private static bool Prefix(Character __instance)
			{
				if (IsSpectator(__instance))
				{
					SpectatorImmunityManager.ApplyDeathImmunity(__instance);
					return false;
				}
				return true;
			}
		}

		private static bool IsSpectator(Character c)
		{
			if ((Object)(object)((c != null) ? ((MonoBehaviourPun)c).photonView : null) == (Object)null)
			{
				return false;
			}
			return GroupManager.IsSpectator(((MonoBehaviourPun)c).photonView.OwnerActorNr);
		}
	}
}
namespace SinnerPeak.Networking
{
	public class NetworkGroupSync : MonoBehaviourPunCallbacks
	{
		private const string GROUPS_KEY = "SP_Groups";

		private const string GROUP_LEADERBOARD_KEY = "SP_GroupLeaderboard";

		public static bool IsDeserializingGroups;

		public static NetworkGroupSync Instance;

		private void Awake()
		{
			Instance = this;
		}

		public static void RequestCreateGroup(string name, Color color, int skinIndex)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			((MonoBehaviourPun)Instance).photonView.RPC("RPC_RequestCreateGroup", (RpcTarget)2, new object[5] { name, color.r, color.g, color.b, skinIndex });
		}

		[PunRPC]
		private void RPC_RequestCreateGroup(string name, float r, float g, float b, int skinIndex)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsMasterClient && !IsDeserializingGroups)
			{
				Color color = default(Color);
				((Color)(ref color))..ctor(r, g, b);
				GroupManager.CreateGroup(name, color, skinIndex);
				BroadcastGroups();
			}
		}

		public static void RequestSetGroupColor(string name, Color color, int skinIndex)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			((MonoBehaviourPun)Instance).photonView.RPC("RPC_RequestSetGroupColor", (RpcTarget)2, new object[5] { name, color.r, color.g, color.b, skinIndex });
		}

		[PunRPC]
		private void RPC_RequestSetGroupColor(string name, float r, float g, float b, int skinIndex)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsMasterClient && !IsDeserializingGroups)
			{
				Color color = default(Color);
				((Color)(ref color))..ctor(r, g, b);
				GroupManager.SetGroupColor(name, color, skinIndex);
				BroadcastGroups();
			}
		}

		public static void RequestAssignPlayer(int actor, string groupName)
		{
			((MonoBehaviourPun)Instance).photonView.RPC("RPC_RequestAssignPlayer", (RpcTarget)2, new object[2] { actor, groupName });
		}

		[PunRPC]
		private void RPC_RequestAssignPlayer(int actor, string groupName)
		{
			if (PhotonNetwork.IsMasterClient && !IsDeserializingGroups)
			{
				GroupManager.AssignPlayerToGroup(actor, groupName);
				BroadcastGroups();
			}
		}

		public static void RequestDeleteGroup(string name)
		{
			((MonoBehaviourPun)Instance).photonView.RPC("RPC_RequestDeleteGroup", (RpcTarget)2, new object[1] { name });
		}

		[PunRPC]
		private void RPC_RequestDeleteGroup(string name)
		{
			if (!PhotonNetwork.IsMasterClient || IsDeserializingGroups || !GroupManager.Groups.ContainsKey(name))
			{
				return;
			}
			List<int> list = new List<int>(GroupManager.Groups[name].Members);
			foreach (int item in list)
			{
				GroupManager.AssignPlayerToGroup(item, "Ungrouped");
			}
			ReviveTokenManager.DeleteGroupToken(name);
			GroupManager.Groups.Remove(name);
			BroadcastGroups();
		}

		public static void BroadcastGroups()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			if (PhotonNetwork.IsMasterClient)
			{
				string text = SerializeGroups();
				Hashtable val = new Hashtable();
				val[(object)"SP_Groups"] = text;
				PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			}
		}

		public static void RequestSetGroupLeaderboard(bool enabled)
		{
			((MonoBehaviourPun)Instance).photonView.RPC("RPC_RequestSetGroupLeaderboard", (RpcTarget)2, new object[1] { enabled });
		}

		[PunRPC]
		private void RPC_RequestSetGroupLeaderboard(bool enabled)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			if (PhotonNetwork.IsMasterClient)
			{
				Hashtable val = new Hashtable();
				val[(object)"SP_GroupLeaderboard"] = (enabled ? 1 : 0);
				PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			}
		}

		public override void OnRoomPropertiesUpdate(Hashtable props)
		{
			if (((Dictionary<object, object>)(object)props).ContainsKey((object)"SP_Groups"))
			{
				DeserializeGroups((string)props[(object)"SP_Groups"]);
				if (((Dic