Decompiled source of CampfireTimer v0.1.0

plugins/wwshare.CampfireTimer.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using Md.PlayerHandler;
using Microsoft.CodeAnalysis;
using MonoDetour;
using MonoDetour.Cil;
using MonoDetour.DetourTypes;
using MonoDetour.HookGen;
using PEAKLib.UI;
using PEAKLib.UI.Elements;
using Peak;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Zorro.Core;
using Zorro.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("wwshare")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("wwshare.CampfireTimer")]
[assembly: AssemblyTitle("wwshare.CampfireTimer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Md.PlayerHandler
{
	internal static class RegisterCharacter
	{
		public delegate void PrefixSignature(ref Character character);

		public delegate void PostfixSignature(ref Character character);

		public static MonoDetourHook Prefix(PrefixSignature hook, MonoDetourConfig? config = null, bool applyByDefault = true, MonoDetourManager? manager = null)
		{
			return (manager ?? DefaultMonoDetourManager.Instance).Hook<PrefixDetour>(Target(), (Delegate)hook, config, applyByDefault);
		}

		public static MonoDetourHook Postfix(PostfixSignature hook, MonoDetourConfig? config = null, bool applyByDefault = true, MonoDetourManager? manager = null)
		{
			return (manager ?? DefaultMonoDetourManager.Instance).Hook<PostfixDetour>(Target(), (Delegate)hook, config, applyByDefault);
		}

		public static MonoDetourHook ILHook(Manipulator manipulator, MonoDetourConfig? config = null, bool applyByDefault = true, MonoDetourManager? manager = null)
		{
			return (manager ?? DefaultMonoDetourManager.Instance).ILHook(Target(), manipulator, config, applyByDefault);
		}

		public static MethodBase Target()
		{
			Type typeFromHandle = typeof(PlayerHandler);
			MethodInfo method = typeFromHandle.GetMethod("RegisterCharacter", (BindingFlags)(-1), null, new Type[1] { typeof(Character) }, null);
			if ((object)method == null)
			{
				throw new MissingMethodException("PlayerHandler", "RegisterCharacter");
			}
			return method;
		}
	}
	internal static class get_OnCharacterRegistered
	{
	}
	internal static class get_NeedRefresh
	{
	}
	internal static class get_Exists
	{
	}
	internal static class _ctor
	{
	}
	internal static class get_Instance
	{
	}
	internal static class GetAllPlayerCharacters
	{
	}
	internal static class RefreshCachedCharacters
	{
	}
	internal static class ClearSessionData
	{
	}
	internal static class IsAnyPlayerNear
	{
	}
	internal static class ClearSceneData
	{
	}
	internal static class RegisterPlayer
	{
	}
	internal static class RegisterPlayerImpl
	{
	}
	internal static class OnNetworkEvent
	{
	}
	internal static class Kick
	{
	}
	internal static class KickRoutine
	{
	}
	internal static class GetPlayer_Photon_Realtime_Player
	{
	}
	internal static class GetPlayer_System_Int32
	{
	}
	internal static class GetUserId
	{
	}
	internal static class GetPlayer_System_String
	{
	}
	internal static class IsBanned
	{
	}
	internal static class TryGetPlayer
	{
	}
	internal static class GetPlayerCharacter
	{
	}
	internal static class HasHadPlayerCharacter
	{
	}
	internal static class AssignMixerGroup
	{
	}
	internal static class Dispose
	{
	}
	internal static class GetAllPlayers
	{
	}
	internal static class TryGetCharacter
	{
	}
	internal static class _cctor
	{
	}
	internal static class _GetAllPlayers_d__40
	{
		internal static class _ctor
		{
		}

		internal static class System_IDisposable_Dispose
		{
		}

		internal static class MoveNext
		{
		}

		internal static class System_Collections_Generic_IEnumerator_Player__get_Current
		{
		}

		internal static class System_Collections_IEnumerator_Reset
		{
		}

		internal static class System_Collections_IEnumerator_get_Current
		{
		}

		internal static class System_Collections_Generic_IEnumerable_Player__GetEnumerator
		{
		}

		internal static class System_Collections_IEnumerable_GetEnumerator
		{
		}
	}
	internal static class _KickRoutine_d__29
	{
		internal static class _ctor
		{
		}

		internal static class System_IDisposable_Dispose
		{
		}

		internal static class MoveNext
		{
		}

		internal static class System_Collections_Generic_IEnumerator_System_Object__get_Current
		{
		}

		internal static class System_Collections_IEnumerator_Reset
		{
		}

		internal static class System_Collections_IEnumerator_get_Current
		{
		}
	}
}
namespace MonoDetour.HookGen
{
	internal static class DefaultMonoDetourManager
	{
		internal static MonoDetourManager Instance { get; } = New();

		internal static MonoDetourManager New()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			return new MonoDetourManager(typeof(DefaultMonoDetourManager).Assembly.GetName().Name);
		}
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
	internal class MonoDetourTargetsAttribute(Type? targetType = null) : Attribute(), IMonoDetourTargets
	{
		public Type? TargetType { get; } = targetType;

		public bool IncludeNestedTypes { get; set; } = true;

		public string[]? Members { get; set; }

		public string[]? MemberNamePrefixes { get; set; }

		public string[]? MemberNameSuffixes { get; set; }

		public bool GenerateControlFlowVariants { get; set; }
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	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")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace PEAKLib.CampfireTimer
{
	public static class CampfireConfig
	{
		public static ConfigEntry<KeyboardShortcut> OpenKey { get; private set; }

		public static ConfigEntry<float> CampfireRadius { get; private set; }

		public static ConfigEntry<float> StatueRadius { get; private set; }

		public static ConfigEntry<bool> ShowInfo { get; private set; }

		public static void Init(ConfigFile config)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			OpenKey = config.Bind<KeyboardShortcut>("General", "OpenKey", new KeyboardShortcut((KeyCode)112, Array.Empty<KeyCode>()), "Key that opens the leaderboard UI.");
			CampfireRadius = config.Bind<float>("General", "CampfireRadius", 3.5f, new ConfigDescription("Trigger radius (meters) around each campfire.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>()));
			StatueRadius = config.Bind<float>("General", "StatueRadius", 4f, new ConfigDescription("Trigger radius (meters) around the summit amulet statue.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>()));
			ShowInfo = config.Bind<bool>("General", "ShowInfo", false, "Show on-screen timing information.");
		}
	}
	public sealed class CampfireNetworkSync : MonoBehaviour
	{
		private Character? character;

		public static event Action<string, string, int, string, int, string, int>? OnResultReceived;

		private void Awake()
		{
			character = ((Component)this).GetComponent<Character>();
		}

		public void BroadcastResult(string peakId, string playerName, int type, string checkpointId, int checkpointIndex, string name, int timeSeconds)
		{
			if (!((Object)(object)character == (Object)null) && !((Object)(object)character.view == (Object)null) && PhotonNetwork.InRoom)
			{
				CampfireTimerPlugin.Log.LogDebug((object)$"Broadcasting result: {playerName} {checkpointId} {timeSeconds}s");
				character.view.RPC("ReceiveResultRPC", (RpcTarget)0, new object[7] { peakId, playerName, type, checkpointId, checkpointIndex, name, timeSeconds });
			}
		}

		[PunRPC]
		private void ReceiveResultRPC(string peakId, string playerName, int type, string checkpointId, int checkpointIndex, string name, int timeSeconds)
		{
			CampfireNetworkSync.OnResultReceived?.Invoke(peakId, playerName, type, checkpointId, checkpointIndex, name, timeSeconds);
		}
	}
	public sealed class CampfireTimer : MonoBehaviour
	{
		private Leaderboard leaderboard;

		private float nextRescanTime;

		private float nextLitPollTime;

		private readonly List<Campfire> trackedCampfires = new List<Campfire>();

		private readonly HashSet<int> activatedSegments = new HashSet<int>();

		private readonly HashSet<int> registeredSegments = new HashSet<int>();

		private readonly Dictionary<string, double> playerSegmentStart = new Dictionary<string, double>();

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

		private Transform? summitStatue;

		private bool localMarkerSet;

		private GameObject? debugRoot;

		private PeakText? debugText;

		private float debugHideTime;

		private const int CampfireCount = 5;

		private const int SummitIndex = 5;

		private const string ModMarkerKey = "wwshare.CampfireTimer";

		public static CampfireTimer? Instance { get; private set; }

		public string CurrentPeakId { get; private set; } = "";

		public string LocalPlayerName
		{
			get
			{
				Character localCharacter = Character.localCharacter;
				if (Object.op_Implicit((Object)(object)localCharacter) && !string.IsNullOrEmpty(localCharacter.characterName))
				{
					return localCharacter.characterName;
				}
				if (PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null && !string.IsNullOrEmpty(PhotonNetwork.LocalPlayer.NickName))
				{
					return PhotonNetwork.LocalPlayer.NickName;
				}
				return "Player";
			}
		}

		public bool HostHasMod
		{
			get
			{
				if (PhotonNetwork.InRoom && PhotonNetwork.MasterClient != null && PhotonNetwork.MasterClient.CustomProperties != null)
				{
					return ((Dictionary<object, object>)(object)PhotonNetwork.MasterClient.CustomProperties).ContainsKey((object)"wwshare.CampfireTimer");
				}
				return false;
			}
		}

		public bool SyncMode => HostHasMod;

		private bool ShouldRunLocalDetection
		{
			get
			{
				if (HostHasMod)
				{
					return PhotonNetwork.IsMasterClient;
				}
				return true;
			}
		}

		public void Initialize(Leaderboard leaderboard)
		{
			this.leaderboard = leaderboard;
			SceneManager.sceneLoaded += OnSceneLoaded;
		}

		private void Awake()
		{
			Instance = this;
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void Start()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			CurrentPeakId = ((Scene)(ref activeScene)).name;
			ScanAll();
			nextRescanTime = Time.time + 3f;
			nextLitPollTime = Time.time + 0.25f;
		}

		private void Update()
		{
			if (OpenKeyPressed())
			{
				LeaderboardPage.Toggle();
			}
			if (ShouldRunLocalDetection && Time.time >= nextRescanTime)
			{
				ScanAll();
				nextRescanTime = Time.time + 3f;
			}
			if (Time.time >= nextLitPollTime)
			{
				EnsureLocalMarker();
				if (ShouldRunLocalDetection)
				{
					PollCampfireLit();
					PollPlayerArrivals();
					PollSummitStatue();
				}
				nextLitPollTime = Time.time + 0.25f;
			}
			UpdateDebugNotification();
		}

		private static bool OpenKeyPressed()
		{
			//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_001d: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = CampfireConfig.OpenKey.Value;
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
			{
				if (!Input.GetKey(modifier))
				{
					return false;
				}
			}
			KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey;
			if (Input.GetKeyDown(mainKey))
			{
				return true;
			}
			Keyboard current2 = Keyboard.current;
			if (current2 != null && TryGetInputSystemKey(mainKey, out var key))
			{
				return ((ButtonControl)current2[key]).wasPressedThisFrame;
			}
			return false;
		}

		private unsafe static bool TryGetInputSystemKey(KeyCode code, out Key key)
		{
			string value = ((object)(*(KeyCode*)(&code))/*cast due to .constrained prefix*/).ToString();
			return Enum.TryParse<Key>(value, ignoreCase: true, out key);
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if ((int)mode == 0)
			{
				if (((Scene)(ref scene)).name == "Airport")
				{
					leaderboard.Clear();
					CurrentPeakId = "";
					trackedCampfires.Clear();
					activatedSegments.Clear();
					registeredSegments.Clear();
					playerSegmentStart.Clear();
					playerAtCampfire.Clear();
					summitStatue = null;
				}
				else
				{
					CurrentPeakId = ((Scene)(ref scene)).name;
					trackedCampfires.Clear();
					activatedSegments.Clear();
					registeredSegments.Clear();
					playerSegmentStart.Clear();
					playerAtCampfire.Clear();
					summitStatue = null;
					ScanAll();
					nextRescanTime = Time.time + 3f;
				}
			}
		}

		private double NowMs()
		{
			if (!PhotonNetwork.IsConnected)
			{
				return (double)Time.time * 1000.0;
			}
			return PhotonNetwork.Time * 1000.0;
		}

		private void ScanAll()
		{
			ScanCampfires();
			summitStatue = FindSummitStatue();
		}

		private void ScanCampfires()
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected I4, but got Unknown
			IOrderedEnumerable<Campfire> orderedEnumerable = from c in Object.FindObjectsByType<Campfire>((FindObjectsInactive)1, (FindObjectsSortMode)0)
				where (int)c.advanceToSegment >= 0 && (int)c.advanceToSegment < 5
				where !registeredSegments.Contains((int)c.advanceToSegment)
				group c by (int)c.advanceToSegment into g
				select g.OrderBy((Campfire c) => ((Component)c).transform.position.y).First() into c
				orderby (int)c.advanceToSegment
				select c;
			foreach (Campfire item in orderedEnumerable)
			{
				int num = (int)item.advanceToSegment;
				string text = CampfireDisplayName(item);
				CampfireTimerPlugin.Log.LogInfo((object)$"Campfire #{num} name='{text}' (override='{item.nameOverride}', go='{((Object)item).name}')");
				registeredSegments.Add(num);
				trackedCampfires.Add(item);
				if (item.Lit)
				{
					activatedSegments.Add(num);
				}
			}
		}

		private string CampfireDisplayName(Campfire campfire)
		{
			try
			{
				string name = campfire.GetName();
				if (!string.IsNullOrEmpty(name) && !name.StartsWith("LOC:"))
				{
					return name;
				}
			}
			catch
			{
			}
			if (!string.IsNullOrEmpty(campfire.nameOverride))
			{
				return campfire.nameOverride;
			}
			if (!string.IsNullOrEmpty(((Object)campfire).name))
			{
				return ((Object)campfire).name;
			}
			return ((object)Unsafe.As<Segment, Segment>(ref campfire.advanceToSegment)/*cast due to .constrained prefix*/).ToString();
		}

		private void PollCampfireLit()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected I4, but got Unknown
			foreach (Campfire trackedCampfire in trackedCampfires)
			{
				if (!((Object)(object)trackedCampfire == (Object)null))
				{
					int num = (int)trackedCampfire.advanceToSegment;
					if (trackedCampfire.Lit && activatedSegments.Add(num))
					{
						OnCampfireLit(num);
					}
				}
			}
		}

		private void OnCampfireLit(int index)
		{
			if (index < 1)
			{
				return;
			}
			double value = NowMs();
			foreach (KeyValuePair<string, int> item in playerAtCampfire)
			{
				if (item.Value == index && !playerSegmentStart.ContainsKey(item.Key))
				{
					playerSegmentStart[item.Key] = value;
				}
			}
			if (CampfireConfig.ShowInfo.Value)
			{
				ShowDebugMessage(Loc.DebugRestart);
			}
		}

		private void PollPlayerArrivals()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected I4, but got Unknown
			foreach (Campfire trackedCampfire in trackedCampfires)
			{
				if ((Object)(object)trackedCampfire == (Object)null)
				{
					continue;
				}
				int index = (int)trackedCampfire.advanceToSegment;
				List<Character> list = trackedCampfire.PlayerCharactersInRadius(CampfireConfig.CampfireRadius.Value);
				if (list == null)
				{
					continue;
				}
				foreach (Character item in list)
				{
					if (!((Object)(object)item == (Object)null))
					{
						string characterName = item.characterName;
						if (!string.IsNullOrEmpty(characterName))
						{
							HandlePlayerArrival(characterName, index, CampfireDisplayName(trackedCampfire));
						}
					}
				}
			}
		}

		private void HandlePlayerArrival(string playerName, int index, string name)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			RecordCheckpoint(playerName, ((object)(Segment)(byte)index/*cast due to .constrained prefix*/).ToString(), name, index, CheckpointType.Campfire);
		}

		private void RecordCheckpoint(string playerName, string checkpointId, string name, int index, CheckpointType type)
		{
			string key = Leaderboard.Key(CurrentPeakId, checkpointId, playerName);
			if (!leaderboard.TryRecord(key))
			{
				return;
			}
			double num = NowMs();
			if (index == 0)
			{
				playerSegmentStart[playerName] = num;
				playerAtCampfire[playerName] = 0;
				return;
			}
			double value;
			double num2 = (playerSegmentStart.TryGetValue(playerName, out value) ? value : num);
			int timeSeconds = (int)Math.Max(0.0, (num - num2) / 1000.0);
			playerSegmentStart.Remove(playerName);
			playerAtCampfire[playerName] = index;
			CheckpointResult checkpointResult = new CheckpointResult
			{
				PeakId = CurrentPeakId,
				PlayerName = playerName,
				Type = type,
				CheckpointId = checkpointId,
				Name = name,
				CheckpointIndex = index,
				TimeSeconds = timeSeconds
			};
			leaderboard.AddResult(checkpointResult);
			CampfireTimerPlugin.Log.LogInfo((object)(playerName + " segment → " + name + ": " + checkpointResult.FormatTime()));
			if (CampfireConfig.ShowInfo.Value)
			{
				ShowDebugMessage(name + " — " + checkpointResult.FormatTime() + " (" + playerName + ")");
			}
			CampfireTimerPlugin.Instance?.PublishResult(checkpointResult);
			if (activatedSegments.Contains(index))
			{
				playerSegmentStart[playerName] = num;
			}
		}

		private Transform? FindSummitStatue()
		{
			ScoutStatue val = Object.FindFirstObjectByType<ScoutStatue>();
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).transform;
			}
			MapHandler instance = Singleton<MapHandler>.Instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)instance.respawnThePeak != (Object)null)
			{
				return instance.respawnThePeak;
			}
			RespawnChest val2 = (from c in Object.FindObjectsByType<RespawnChest>((FindObjectsInactive)1, (FindObjectsSortMode)0)
				orderby ((Component)c).transform.position.y descending
				select c).FirstOrDefault();
			if (val2 == null)
			{
				return null;
			}
			return ((Component)val2).transform;
		}

		private void PollSummitStatue()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)summitStatue == (Object)null)
			{
				return;
			}
			Vector3 position = summitStatue.position;
			foreach (Character allCharacter in Character.AllCharacters)
			{
				if (!((Object)(object)allCharacter == (Object)null))
				{
					string characterName = allCharacter.characterName;
					if (!string.IsNullOrEmpty(characterName) && !(Vector3.Distance(allCharacter.Center, position) > CampfireConfig.StatueRadius.Value))
					{
						RecordCheckpoint(characterName, "Peak", "Summit", 5, CheckpointType.Summit);
					}
				}
			}
		}

		private void EnsureLocalMarker()
		{
			//IL_0017: 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 (!localMarkerSet && PhotonNetwork.InRoom && PhotonNetwork.LocalPlayer != null)
			{
				Hashtable val = new Hashtable { [(object)"wwshare.CampfireTimer"] = (byte)1 };
				PhotonNetwork.LocalPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
				localMarkerSet = true;
				CampfireTimerPlugin.Log.LogDebug((object)"Published local mod marker.");
			}
		}

		public void RecordArrival(CheckpointTrigger trigger)
		{
			if (trigger.Type != CheckpointType.Campfire)
			{
				RecordCheckpoint(LocalPlayerName, trigger.CheckpointId, trigger.Name, trigger.CheckpointIndex, trigger.Type);
			}
		}

		public bool ReceiveResult(string peakId, string playerName, int type, string checkpointId, int checkpointIndex, string name, int timeSeconds)
		{
			string key = Leaderboard.Key(peakId, checkpointId, playerName);
			if (!leaderboard.TryRecord(key))
			{
				CampfireTimerPlugin.Log.LogDebug((object)("Skipping duplicate result: " + playerName + " " + checkpointId));
				return false;
			}
			CampfireTimerPlugin.Log.LogInfo((object)$"Recorded result: {playerName} {checkpointId} {timeSeconds}s");
			leaderboard.AddResult(new CheckpointResult
			{
				PeakId = peakId,
				PlayerName = playerName,
				Type = (CheckpointType)type,
				CheckpointId = checkpointId,
				Name = name,
				CheckpointIndex = checkpointIndex,
				TimeSeconds = timeSeconds
			});
			return true;
		}

		private void BuildDebugUi()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0084: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			debugRoot = new GameObject("CampfireDebugNotify", new Type[3]
			{
				typeof(Canvas),
				typeof(CanvasScaler),
				typeof(GraphicRaycaster)
			});
			Object.DontDestroyOnLoad((Object)(object)debugRoot);
			Canvas component = debugRoot.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 1000;
			CanvasScaler component2 = debugRoot.GetComponent<CanvasScaler>();
			component2.uiScaleMode = (ScaleMode)1;
			component2.referenceResolution = new Vector2(1920f, 1080f);
			component2.matchWidthOrHeight = 1f;
			debugText = ElementExtensions.SetPosition<PeakText>(ElementExtensions.AlignToParent<PeakText>(ElementExtensions.ParentTo<PeakText>(MenuAPI.CreateText("", "DebugText"), debugRoot.transform), (UIAlignment)1), new Vector2(0f, -80f)).SetFontSize(36f).SetColor(new Color(1f, 0.9f, 0.3f));
			debugRoot.SetActive(false);
		}

		public void ShowDebugMessage(string message)
		{
			if (CampfireConfig.ShowInfo.Value)
			{
				if ((Object)(object)debugRoot == (Object)null)
				{
					BuildDebugUi();
				}
				if (!((Object)(object)debugText == (Object)null))
				{
					debugText.SetText(message);
					debugRoot.SetActive(true);
					debugHideTime = Time.time + 3f;
				}
			}
		}

		private void UpdateDebugNotification()
		{
			if ((Object)(object)debugRoot != (Object)null && debugRoot.activeSelf && Time.time >= debugHideTime)
			{
				debugRoot.SetActive(false);
			}
		}
	}
	[MonoDetourTargets(typeof(PlayerHandler))]
	internal static class CharacterHooks
	{
		public static event Action<Character>? OnCharacterAdded;

		[MonoDetourHookInitialize]
		private static void Init()
		{
			RegisterCharacter.Postfix(Postfix_RegisterCharacter);
		}

		private static void Postfix_RegisterCharacter(ref Character character)
		{
			CharacterHooks.OnCharacterAdded?.Invoke(character);
		}
	}
	public enum CheckpointType
	{
		Base,
		Campfire,
		Summit
	}
	public sealed class CheckpointResult
	{
		public string PeakId { get; set; } = "";

		public string PlayerName { get; set; } = "Unknown";

		public CheckpointType Type { get; set; }

		public string CheckpointId { get; set; } = "";

		public string Name { get; set; } = "";

		public int CheckpointIndex { get; set; }

		public int TimeSeconds { get; set; }

		public string FormatTime()
		{
			int num = TimeSeconds / 60;
			int num2 = TimeSeconds % 60;
			return $"{num}:{num2:00}";
		}
	}
	public sealed class CheckpointTrigger : MonoBehaviour
	{
		public CheckpointType Type { get; internal set; }

		public string CheckpointId { get; internal set; } = "";

		public string Name { get; internal set; } = "";

		public int CheckpointIndex { get; internal set; }

		private void OnTriggerEnter(Collider other)
		{
			Character componentInParent = ((Component)other).GetComponentInParent<Character>();
			if (!((Object)(object)componentInParent == (Object)null) && componentInParent.IsLocal)
			{
				CampfireTimer.Instance?.RecordArrival(this);
			}
		}
	}
	public sealed class Leaderboard
	{
		private readonly List<CheckpointResult> results = new List<CheckpointResult>();

		private readonly HashSet<string> recordedKeys = new HashSet<string>();

		public IReadOnlyList<CheckpointResult> GetRanking(string peakId, int checkpointIndex)
		{
			return (from r in results
				where r.PeakId == peakId && r.CheckpointIndex == checkpointIndex
				orderby r.TimeSeconds
				select r).ToList();
		}

		public IReadOnlyList<CheckpointResult> GetForPeak(string peakId)
		{
			return (from r in results
				where r.PeakId == peakId
				orderby r.CheckpointIndex, r.TimeSeconds
				select r).ToList();
		}

		public bool TryRecord(string key)
		{
			return recordedKeys.Add(key);
		}

		public void AddResult(CheckpointResult result)
		{
			results.Add(result);
		}

		public void Clear()
		{
			results.Clear();
			recordedKeys.Clear();
		}

		public static string Key(string peakId, string checkpointId, string playerName)
		{
			return playerName + "|" + peakId + "|" + checkpointId;
		}
	}
	public static class LeaderboardPage
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__Refresh;
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__5_0;

			public static UnityAction<float> <>9__5_1;

			public static UnityAction<float> <>9__5_2;

			public static Func<CheckpointResult, int> <>9__10_0;

			public static Func<IGrouping<int, CheckpointResult>, int> <>9__10_1;

			internal void <Build>b__5_0()
			{
				CampfireConfig.ShowInfo.Value = !CampfireConfig.ShowInfo.Value;
				showInfoButton.SetText(ShowInfoLabel());
			}

			internal void <Build>b__5_1(float v)
			{
				CampfireConfig.CampfireRadius.Value = v;
			}

			internal void <Build>b__5_2(float v)
			{
				CampfireConfig.StatueRadius.Value = v;
			}

			internal int <Refresh>b__10_0(CheckpointResult r)
			{
				return r.CheckpointIndex;
			}

			internal int <Refresh>b__10_1(IGrouping<int, CheckpointResult> g)
			{
				return g.Key;
			}
		}

		private static PeakChildPage? page;

		private static RectTransform? content;

		private static PeakText? headerText;

		private static PauseMenuHandler? pauseMenuHandler;

		private static PeakMenuButton? showInfoButton;

		public static void Build(Transform parent)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Expected O, but got Unknown
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)page != (Object)null)
			{
				return;
			}
			pauseMenuHandler = ((Component)parent).GetComponentInParent<PauseMenuHandler>();
			UIPage component = ((Component)parent).GetComponent<UIPage>();
			if ((Object)(object)pauseMenuHandler == (Object)null || (Object)(object)component == (Object)null)
			{
				return;
			}
			page = MenuAPI.CreateChildPage("CampfireLeaderboardPage", component);
			PeakChildPage? obj = page;
			object obj2 = <>O.<0>__Refresh;
			if (obj2 == null)
			{
				UnityAction val = Refresh;
				<>O.<0>__Refresh = val;
				obj2 = (object)val;
			}
			obj.SetOnOpen((UnityAction)obj2);
			headerText = ElementExtensions.SetPosition<PeakText>(ElementExtensions.ParentTo<PeakText>(MenuAPI.CreateText(Loc.RankingsTitle, "Header"), (Component)(object)page), new Vector2(60f, -40f)).SetFontSize(44f);
			PeakMenuButton val2 = ElementExtensions.SetPosition<PeakMenuButton>(ElementExtensions.ParentTo<PeakMenuButton>(MenuAPI.CreateMenuButton(Loc.Back).SetColor(new Color(0.5189f, 0.1297f, 0.1718f), true), (Component)(object)page), new Vector2(120f, -160f)).SetWidth(120f);
			page.SetBackButton(((Component)val2).GetComponent<Button>());
			showInfoButton = ElementExtensions.SetPosition<PeakMenuButton>(ElementExtensions.ParentTo<PeakMenuButton>(MenuAPI.CreateMenuButton(ShowInfoLabel()).SetColor(new Color(0.3919f, 0.1843f, 0.6235f), true), (Component)(object)page), new Vector2(300f, -160f)).SetWidth(240f);
			PeakMenuButton? obj3 = showInfoButton;
			object obj4 = <>c.<>9__5_0;
			if (obj4 == null)
			{
				UnityAction val3 = delegate
				{
					CampfireConfig.ShowInfo.Value = !CampfireConfig.ShowInfo.Value;
					showInfoButton.SetText(ShowInfoLabel());
				};
				<>c.<>9__5_0 = val3;
				obj4 = (object)val3;
			}
			obj3.OnClick((UnityAction)obj4);
			CreateSlider(((Component)page).transform, Loc.CampfireRadiusLabel, CampfireConfig.CampfireRadius.Value, new Vector2(60f, -220f), delegate(float v)
			{
				CampfireConfig.CampfireRadius.Value = v;
			});
			CreateSlider(((Component)page).transform, Loc.StatueRadiusLabel, CampfireConfig.StatueRadius.Value, new Vector2(60f, -300f), delegate(float v)
			{
				CampfireConfig.StatueRadius.Value = v;
			});
			PeakScrollableContent val4 = ElementExtensions.SetSize<PeakScrollableContent>(ElementExtensions.SetPosition<PeakScrollableContent>(ElementExtensions.SetPivot<PeakScrollableContent>(ElementExtensions.SetAnchorMinMax<PeakScrollableContent>(ElementExtensions.ParentTo<PeakScrollableContent>(MenuAPI.CreateScrollableContent("RankingsScroll"), (Component)(object)page), new Vector2(0f, 1f)), new Vector2(0f, 1f)), new Vector2(60f, -380f)), new Vector2(1100f, 600f));
			content = val4.Content;
			((Component)page).gameObject.SetActive(false);
		}

		private static string ShowInfoLabel()
		{
			if (!CampfireConfig.ShowInfo.Value)
			{
				return Loc.ShowInfoOff;
			}
			return Loc.ShowInfoOn;
		}

		public static void Toggle()
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			if ((Object)(object)page == (Object)null || (Object)(object)pauseMenuHandler == (Object)null)
			{
				return;
			}
			GUIManager instance = GUIManager.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.pauseMenu == (Object)null)
			{
				return;
			}
			if (((Component)page).gameObject.activeInHierarchy)
			{
				((UIPageHandler)pauseMenuHandler).TransistionToPage<PauseMenuMainPage>();
				return;
			}
			if (!instance.pauseMenu.activeSelf)
			{
				instance.pauseMenu.SetActive(true);
			}
			((UIPageHandler)pauseMenuHandler).TransistionToPage((UIPage)(object)page, (PageTransistion)new SetActivePageTransistion());
		}

		private static void CreateSlider(Transform parent, string label, float current, Vector2 position, UnityAction<float> onChanged)
		{
			//IL_000d: 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_0049: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_0138: 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_0160: Expected O, but got Unknown
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Expected O, but got Unknown
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Expected O, but got Unknown
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			ElementExtensions.SetPosition<PeakText>(ElementExtensions.ParentTo<PeakText>(MenuAPI.CreateText(label, label), parent), position).SetFontSize(22f);
			GameObject val = new GameObject("Slider", new Type[2]
			{
				typeof(RectTransform),
				typeof(Slider)
			});
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = new Vector2(0f, 1f);
			component.pivot = new Vector2(0f, 1f);
			component.anchoredPosition = position + new Vector2(0f, -32f);
			component.sizeDelta = new Vector2(420f, 20f);
			GameObject val2 = new GameObject("Background", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val2.transform.SetParent(val.transform, false);
			Stretch(val2.GetComponent<RectTransform>());
			((Graphic)val2.GetComponent<Image>()).color = new Color(1f, 1f, 1f, 0.25f);
			GameObject val3 = new GameObject("Fill Area", new Type[1] { typeof(RectTransform) });
			val3.transform.SetParent(val.transform, false);
			Stretch(val3.GetComponent<RectTransform>(), 8f);
			GameObject val4 = new GameObject("Fill", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val4.transform.SetParent(val3.transform, false);
			Stretch(val4.GetComponent<RectTransform>());
			((Graphic)val4.GetComponent<Image>()).color = new Color(0.185f, 0.394f, 0.6226f);
			GameObject val5 = new GameObject("Handle Slide Area", new Type[1] { typeof(RectTransform) });
			val5.transform.SetParent(val.transform, false);
			Stretch(val5.GetComponent<RectTransform>(), 8f);
			GameObject val6 = new GameObject("Handle", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val6.transform.SetParent(val5.transform, false);
			RectTransform component2 = val6.GetComponent<RectTransform>();
			component2.sizeDelta = new Vector2(20f, 20f);
			((Graphic)val6.GetComponent<Image>()).color = Color.white;
			Slider component3 = val.GetComponent<Slider>();
			component3.minValue = 1f;
			component3.maxValue = 20f;
			component3.value = current;
			component3.fillRect = val4.GetComponent<RectTransform>();
			component3.handleRect = component2;
			((Selectable)component3).targetGraphic = (Graphic)(object)val6.GetComponent<Image>();
			component3.direction = (Direction)0;
			((UnityEvent<float>)(object)component3.onValueChanged).AddListener(onChanged);
		}

		private static void Stretch(RectTransform rect, float horizontalInset = 0f, float verticalInset = 0f)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.one;
			rect.offsetMin = new Vector2(horizontalInset, verticalInset);
			rect.offsetMax = new Vector2(0f - horizontalInset, 0f - verticalInset);
		}

		private static void Refresh()
		{
			if ((Object)(object)page == (Object)null || (Object)(object)content == (Object)null || (Object)(object)headerText == (Object)null)
			{
				return;
			}
			for (int num = ((Transform)content).childCount - 1; num >= 0; num--)
			{
				Object.Destroy((Object)(object)((Component)((Transform)content).GetChild(num)).gameObject);
			}
			string text = CampfireTimer.Instance?.CurrentPeakId ?? "";
			headerText.SetText(Loc.RankingsTitle + " — " + text);
			IReadOnlyList<CheckpointResult> forPeak = CampfireTimerPlugin.Instance.Leaderboard.GetForPeak(text);
			if (forPeak.Count == 0)
			{
				ElementExtensions.ParentTo<PeakText>(MenuAPI.CreateText(Loc.Empty, "Empty"), (Transform)(object)content).SetFontSize(26f);
				return;
			}
			foreach (IGrouping<int, CheckpointResult> item in from r in forPeak
				group r by r.CheckpointIndex into g
				orderby g.Key
				select g)
			{
				CheckpointResult checkpointResult = item.First();
				string title = ((checkpointResult.Type == CheckpointType.Summit) ? Loc.SummitLabel : Loc.CampfireLabel(checkpointResult.CheckpointIndex, Loc.CampfireName(checkpointResult.Name)));
				AddSection(content, title, item);
			}
		}

		private static void AddSection(RectTransform parent, string title, IEnumerable<CheckpointResult> results)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Expected O, but got Unknown
			PeakButton val = ElementExtensions.SetSize<PeakButton>(ElementExtensions.ParentTo<PeakButton>(MenuAPI.CreateButton(title), (Transform)(object)parent), new Vector2(1100f, 44f));
			((TMP_Text)val.Text.TextMesh).enableAutoSizing = false;
			((TMP_Text)val.Text.TextMesh).fontSize = 26f;
			((TMP_Text)val.Text.TextMesh).fontStyle = (FontStyles)0;
			((TMP_Text)val.Text.TextMesh).alignment = (TextAlignmentOptions)513;
			GameObject bodyGo = new GameObject("Body", new Type[3]
			{
				typeof(RectTransform),
				typeof(VerticalLayoutGroup),
				typeof(ContentSizeFitter)
			});
			bodyGo.transform.SetParent((Transform)(object)parent, false);
			RectTransform component = bodyGo.GetComponent<RectTransform>();
			component.sizeDelta = new Vector2(1100f, 0f);
			VerticalLayoutGroup component2 = bodyGo.GetComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)component2).childControlHeight = false;
			((HorizontalOrVerticalLayoutGroup)component2).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)component2).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)component2).childForceExpandWidth = true;
			((LayoutGroup)component2).padding = new RectOffset(30, 0, 4, 4);
			((HorizontalOrVerticalLayoutGroup)component2).spacing = 2f;
			ContentSizeFitter component3 = bodyGo.GetComponent<ContentSizeFitter>();
			component3.verticalFit = (FitMode)2;
			int num = 0;
			foreach (CheckpointResult result in results)
			{
				num++;
				ElementExtensions.ParentTo<PeakText>(MenuAPI.CreateText(Loc.Row(num, result.PlayerName, result.FormatTime()), "Row"), (Transform)(object)component).SetFontSize(24f);
			}
			bodyGo.SetActive(false);
			val.OnClick((UnityAction)delegate
			{
				bodyGo.SetActive(!bodyGo.activeSelf);
				LayoutRebuilder.ForceRebuildLayoutImmediate(parent);
			});
		}
	}
	public static class Loc
	{
		private static readonly Dictionary<string, string> CampfireZh = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["flame"] = "沙滩",
			["beach"] = "沙滩",
			["tropical"] = "雨林",
			["tropics"] = "雨林",
			["alpine"] = "方山",
			["caldera"] = "火山",
			["volcano"] = "火山",
			["kiln"] = "熔炉",
			["the kiln"] = "熔炉",
			["thekiln"] = "熔炉",
			["peak"] = "顶峰",
			["summit"] = "顶峰",
			["temple"] = "神庙",
			["start"] = "起点营地",
			["base"] = "起点营地"
		};

		public static bool IsChinese => (int)LocalizedText.CURRENT_LANGUAGE == 9;

		public static string RankingsTitle => T("Climb Rankings", "攀登排名");

		public static string Back => T("Back", "返回");

		public static string Empty => T("No times recorded for this peak yet.", "这座山还没有计时记录。");

		public static string SummitLabel => T("Summit", "顶峰");

		public static string ShowInfoOff => T("Show info: OFF", "显示信息:关");

		public static string ShowInfoOn => T("Show info: ON", "显示信息:开");

		public static string CampfireRadiusLabel => T("Campfire radius", "篝火触发范围");

		public static string StatueRadiusLabel => T("Statue radius", "雕像触发范围");

		public static string DebugStart => T("Timer started", "开始计时");

		public static string DebugRestart => T("Timer restarted", "重启计时");

		public static string T(string en, string zh)
		{
			if (!IsChinese)
			{
				return en;
			}
			return zh;
		}

		public static string Row(int rank, string player, string time)
		{
			return $"{rank}. {player} — {time}";
		}

		public static string CampfireLabel(int number, string name)
		{
			return T($"Campfire {number}: {name}", $"篝火 {number}:{name}");
		}

		public static string CampfireName(string name)
		{
			if (!IsChinese || string.IsNullOrEmpty(name))
			{
				return name;
			}
			string key = name.Trim().ToLowerInvariant();
			if (!CampfireZh.TryGetValue(key, out string value))
			{
				return name;
			}
			return value;
		}
	}
	[BepInPlugin("com.github.wwshare.CampfireTimer", "wwshare.CampfireTimer", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class CampfireTimerPlugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static BuilderDelegate <0>__Build;
		}

		private const string PluginName = "wwshare.CampfireTimer";

		private CampfireTimer timer;

		private CampfireNetworkSync? localSync;

		public static CampfireTimerPlugin Instance { get; private set; } = null;

		internal static ManualLogSource Log { get; } = Logger.CreateLogSource("wwshare.CampfireTimer");

		internal Leaderboard Leaderboard { get; private set; }

		private void Awake()
		{
			//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_008f: Expected O, but got Unknown
			Instance = this;
			CampfireConfig.Init(((BaseUnityPlugin)this).Config);
			MonoDetourManager.InvokeHookInitializers(typeof(CampfireTimerPlugin).Assembly);
			Leaderboard = new Leaderboard();
			timer = ((Component)this).gameObject.AddComponent<CampfireTimer>();
			timer.Initialize(Leaderboard);
			CampfireNetworkSync.OnResultReceived += OnResultReceived;
			CharacterHooks.OnCharacterAdded += OnCharacterAdded;
			object obj = <>O.<0>__Build;
			if (obj == null)
			{
				BuilderDelegate val = LeaderboardPage.Build;
				<>O.<0>__Build = val;
				obj = (object)val;
			}
			MenuAPI.AddToPauseMenu((BuilderDelegate)obj);
			Log.LogInfo((object)"Plugin wwshare.CampfireTimer is loaded!");
		}

		private void OnDestroy()
		{
			CampfireNetworkSync.OnResultReceived -= OnResultReceived;
			CharacterHooks.OnCharacterAdded -= OnCharacterAdded;
		}

		private void OnCharacterAdded(Character character)
		{
			CampfireNetworkSync campfireNetworkSync = ((Component)character).gameObject.GetComponent<CampfireNetworkSync>();
			if ((Object)(object)campfireNetworkSync == (Object)null)
			{
				campfireNetworkSync = ((Component)character).gameObject.AddComponent<CampfireNetworkSync>();
			}
			if (character.IsLocal)
			{
				localSync = campfireNetworkSync;
			}
		}

		private void OnResultReceived(string peakId, string playerName, int type, string checkpointId, int checkpointIndex, string name, int timeSeconds)
		{
			timer.ReceiveResult(peakId, playerName, type, checkpointId, checkpointIndex, name, timeSeconds);
		}

		public void PublishResult(CheckpointResult result)
		{
			if (!timer.SyncMode)
			{
				return;
			}
			if ((Object)(object)localSync == (Object)null)
			{
				Character localCharacter = Character.localCharacter;
				if ((Object)(object)localCharacter != (Object)null)
				{
					localSync = ((Component)localCharacter).gameObject.GetComponent<CampfireNetworkSync>();
				}
			}
			if (!((Object)(object)localSync == (Object)null) && PhotonNetwork.InRoom)
			{
				localSync.BroadcastResult(result.PeakId, result.PlayerName, (int)result.Type, result.CheckpointId, result.CheckpointIndex, result.Name, result.TimeSeconds);
			}
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ConstantExpectedAttribute : Attribute
	{
		public object? Min { get; set; }

		public object? Max { get; set; }
	}
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ExperimentalAttribute : Attribute
	{
		public string DiagnosticId { get; }

		public string? UrlFormat { get; set; }

		public ExperimentalAttribute(string diagnosticId)
		{
			DiagnosticId = diagnosticId;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullAttribute : Attribute
	{
		public string[] Members { get; }

		public MemberNotNullAttribute(string member)
		{
			Members = new string[1] { member };
		}

		public MemberNotNullAttribute(params string[] members)
		{
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
	[ExcludeFromCodeCoverage]
	internal sealed class MemberNotNullWhenAttribute : Attribute
	{
		public bool ReturnValue { get; }

		public string[] Members { get; }

		public MemberNotNullWhenAttribute(bool returnValue, string member)
		{
			ReturnValue = returnValue;
			Members = new string[1] { member };
		}

		public MemberNotNullWhenAttribute(bool returnValue, params string[] members)
		{
			ReturnValue = returnValue;
			Members = members;
		}
	}
	[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SetsRequiredMembersAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class StringSyntaxAttribute : Attribute
	{
		public const string CompositeFormat = "CompositeFormat";

		public const string DateOnlyFormat = "DateOnlyFormat";

		public const string DateTimeFormat = "DateTimeFormat";

		public const string EnumFormat = "EnumFormat";

		public const string GuidFormat = "GuidFormat";

		public const string Json = "Json";

		public const string NumericFormat = "NumericFormat";

		public const string Regex = "Regex";

		public const string TimeOnlyFormat = "TimeOnlyFormat";

		public const string TimeSpanFormat = "TimeSpanFormat";

		public const string Uri = "Uri";

		public const string Xml = "Xml";

		public string Syntax { get; }

		public object?[] Arguments { get; }

		public StringSyntaxAttribute(string syntax)
		{
			Syntax = syntax;
			Arguments = new object[0];
		}

		public StringSyntaxAttribute(string syntax, params object?[] arguments)
		{
			Syntax = syntax;
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class UnscopedRefAttribute : Attribute
	{
	}
}
namespace System.Runtime.Versioning
{
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresPreviewFeaturesAttribute : Attribute
	{
		public string? Message { get; }

		public string? Url { get; set; }

		public RequiresPreviewFeaturesAttribute()
		{
		}

		public RequiresPreviewFeaturesAttribute(string? message)
		{
			Message = message;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CallerArgumentExpressionAttribute : Attribute
	{
		public string ParameterName { get; }

		public CallerArgumentExpressionAttribute(string parameterName)
		{
			ParameterName = parameterName;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CollectionBuilderAttribute : Attribute
	{
		public Type BuilderType { get; }

		public string MethodName { get; }

		public CollectionBuilderAttribute(Type builderType, string methodName)
		{
			BuilderType = builderType;
			MethodName = methodName;
		}
	}
	[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class CompilerFeatureRequiredAttribute : Attribute
	{
		public const string RefStructs = "RefStructs";

		public const string RequiredMembers = "RequiredMembers";

		public string FeatureName { get; }

		public bool IsOptional { get; set; }

		public CompilerFeatureRequiredAttribute(string featureName)
		{
			FeatureName = featureName;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute
	{
		public string[] Arguments { get; }

		public InterpolatedStringHandlerArgumentAttribute(string argument)
		{
			Arguments = new string[1] { argument };
		}

		public InterpolatedStringHandlerArgumentAttribute(params string[] arguments)
		{
			Arguments = arguments;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class InterpolatedStringHandlerAttribute : Attribute
	{
	}
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal static class IsExternalInit
	{
	}
	[AttributeUsage(AttributeTargets.Method, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ModuleInitializerAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class OverloadResolutionPriorityAttribute : Attribute
	{
		public int Priority { get; }

		public OverloadResolutionPriorityAttribute(int priority)
		{
			Priority = priority;
		}
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class ParamCollectionAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiredMemberAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
	[EditorBrowsable(EditorBrowsableState.Never)]
	[ExcludeFromCodeCoverage]
	internal sealed class RequiresLocationAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)]
	[ExcludeFromCodeCoverage]
	internal sealed class SkipLocalsInitAttribute : Attribute
	{
	}
}