Decompiled source of Varkour v0.5.1

plugins/Varkour.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
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 HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Splatform;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;
using Varkour.Core;
using Varkour.Editor;
using Varkour.Items;
using Varkour.Map;
using Varkour.Net;
using Varkour.Runs;
using Varkour.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Dillon")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Build parkour courses in Valheim, run them, and compete on server-side leaderboards.")]
[assembly: AssemblyFileVersion("0.5.1.0")]
[assembly: AssemblyInformationalVersion("0.5.1")]
[assembly: AssemblyProduct("Varkour")]
[assembly: AssemblyTitle("Varkour")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.5.1.0")]
[module: UnverifiableCode]
namespace Varkour
{
	[BepInPlugin("dillon.varkour", "Varkour", "0.5.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal sealed class VarkourPlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private const float ErrorLogInterval = 5f;

		private static readonly Action ServerTick = ServerStore.Tick;

		private static readonly Action LabelsTick = ZoneLabels.LateTick;

		private static readonly string[] ClientTickNames = new string[8] { "Welcome", "ClientCourses", "ModeMachine", "CourseEditor", "RunController", "ZoneVisuals", "VarkourWindow", "CoursePins" };

		private static readonly Action[] ClientTicks = new Action[8]
		{
			Welcome.Tick,
			ClientCourses.Tick,
			ModeMachine.Tick,
			CourseEditor.Tick,
			RunController.Tick,
			ZoneVisuals.Tick,
			VarkourWindow.Tick,
			CoursePins.Tick
		};

		private readonly Dictionary<string, float> _lastErrorLog = new Dictionary<string, float>();

		private Harmony _harmony;

		private bool _headless;

		private void Awake()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			_headless = GUIManager.IsHeadless();
			VarkourConfig.Bind(((BaseUnityPlugin)this).Config);
			VarkourLocalization.Register();
			VarkourNet.Register();
			HardcoreParkour.Register(_headless);
			PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable;
			if (!_headless)
			{
				CourseEditor.Init();
				RunController.Init();
				VarkourWindow.Init();
			}
			_harmony = new Harmony("dillon.varkour");
			_harmony.PatchAll(typeof(VarkourPlugin).Assembly);
			Log.LogInfo((object)("Varkour 0.5.1 loaded (" + (_headless ? "dedicated server" : "client") + ")."));
		}

		private void OnVanillaPrefabsAvailable()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
			MarkerPieces.Register();
			PoleItem.Register();
		}

		private void Update()
		{
			Safe("ServerStore", ServerTick);
			if (!_headless)
			{
				for (int i = 0; i < ClientTicks.Length; i++)
				{
					Safe(ClientTickNames[i], ClientTicks[i]);
				}
			}
		}

		private void LateUpdate()
		{
			if (!_headless)
			{
				Safe("ZoneLabels", LabelsTick);
			}
		}

		private void OnDestroy()
		{
			ServerStore.Unload();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		internal static void LogVerbose(string message)
		{
			if (VarkourConfig.VerboseLogging != null && VarkourConfig.VerboseLogging.Value)
			{
				Log.LogInfo((object)message);
			}
		}

		private void Safe(string name, Action tick)
		{
			try
			{
				tick();
			}
			catch (Exception arg)
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (!_lastErrorLog.TryGetValue(name, out var value) || realtimeSinceStartup - value > 5f)
				{
					_lastErrorLog[name] = realtimeSinceStartup;
					Log.LogError((object)$"{name} tick failed: {arg}");
				}
			}
		}
	}
}
namespace Varkour.UI
{
	internal static class VarkourWindow
	{
		private enum Tab
		{
			Courses,
			Leaderboards,
			Info
		}

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

			public static Action <>9__61_0;

			public static Action <>9__61_1;

			public static Action <>9__61_2;

			public static UnityAction<bool> <>9__61_3;

			public static UnityAction <>9__61_4;

			public static UnityAction <>9__64_0;

			public static UnityAction <>9__64_1;

			public static UnityAction<string> <>9__69_0;

			public static Action <>9__69_1;

			public static Action <>9__74_0;

			internal void <EnsureBuilt>b__61_0()
			{
				SetTab(Tab.Courses);
			}

			internal void <EnsureBuilt>b__61_1()
			{
				SetTab(Tab.Leaderboards);
			}

			internal void <EnsureBuilt>b__61_2()
			{
				SetTab(Tab.Info);
			}

			internal void <EnsureBuilt>b__61_3(bool v)
			{
				RunController.Practice = v;
			}

			internal void <EnsureBuilt>b__61_4()
			{
				SetCursorActive(active: false);
			}

			internal void <BuildConfirm>b__64_0()
			{
				_confirm.SetActive(false);
				Action confirmAction = _confirmAction;
				_confirmAction = null;
				confirmAction?.Invoke();
			}

			internal void <BuildConfirm>b__64_1()
			{
				_confirm.SetActive(false);
				_confirmAction = null;
			}

			internal void <BuildZoneList>b__69_0(string _)
			{
				ApplyRename();
			}

			internal void <BuildZoneList>b__69_1()
			{
				ApplyRename();
				CourseEditor.Close();
				_dirty = true;
			}

			internal void <BuildLeaderboard>b__74_0()
			{
				_selectedBoardCourse = null;
			}
		}

		private const float Width = 900f;

		private const float Height = 640f;

		private const float RowHeight = 34f;

		private const int FontSize = 18;

		private const float EdgeInset = 30f;

		private const float TabGap = 12f;

		private const float TabY = -85f;

		private const float TabHeight = 36f;

		private const float FooterBottom = 22f;

		private const float HintHeight = 24f;

		private const float CloseHeight = 36f;

		private const float CloseWidth = 160f;

		private const float FooterGap = 6f;

		private const float FocusButtonWidth = 230f;

		private const float HintY = 34f;

		private const float CloseY = 70f;

		private const float ListBottom = 100f;

		private static readonly List<Course> MyDrafts = new List<Course>();

		private static GameObject _panel;

		private static RectTransform _content;

		private static InputField _nameInput;

		private static GameObject _newCourseRow;

		private static Toggle _practiceToggle;

		private static Text _title;

		private static GameObject _confirm;

		private static Text _confirmText;

		private static Action _confirmAction;

		private static Tab _tab = Tab.Courses;

		private static string _selectedBoardCourse;

		private static int _builtRevision = -1;

		private static VarkourMode _builtMode;

		private static Tab _builtTab;

		private static string _builtBoardCourse;

		private static bool _dirty = true;

		private static CanvasGroup _panelGroup;

		private static Text _cursorHint;

		private static GameObject _focusButton;

		private static Button _addSpotButton;

		private static InputField _renameInput;

		private static Course _renameCourse;

		private static string _renameTextInFlight;

		private static bool _renameFocusInFlight;

		private static bool _rememberedOpen = true;

		private static bool _rememberedFocus = true;

		private static bool _typingBlock;

		private const float MoveButtonWidth = 34f;

		public static bool IsOpen
		{
			get
			{
				if ((Object)(object)_panel != (Object)null)
				{
					return _panel.activeSelf;
				}
				return false;
			}
		}

		public static bool CursorActive { get; private set; }

		public static void Init()
		{
			ModeMachine.Changed += OnModeChanged;
		}

		private static void OnModeChanged(VarkourMode previous, VarkourMode next)
		{
			if (next == VarkourMode.Off)
			{
				_rememberedOpen = IsOpen;
				_rememberedFocus = IsOpen && CursorActive;
				return;
			}
			if (previous == VarkourMode.Off && next == VarkourMode.Idle && _rememberedOpen && !IsOpen && !UiState.VanillaMenuOpen())
			{
				Open();
				SetCursorActive(_rememberedFocus);
				return;
			}
			if (next == VarkourMode.Editing && IsOpen)
			{
				SetCursorActive(active: false);
			}
			if (previous == VarkourMode.Editing)
			{
				ApplyRename();
			}
		}

		private static void ApplyRename()
		{
			if ((Object)(object)_renameInput != (Object)null && _renameCourse != null)
			{
				CourseEditor.Rename(_renameCourse, _renameInput.text);
			}
		}

		public static void Tick()
		{
			VarkourMode current = ModeMachine.Current;
			bool flag = current == VarkourMode.Idle || current == VarkourMode.Editing;
			if (IsOpen && !flag)
			{
				Close();
				return;
			}
			if (VarkourInput.Down(VarkourConfig.WindowKey))
			{
				VarkourPlugin.LogVerbose($"Window key: mode={current}, open={IsOpen}, menuOpen={UiState.VanillaMenuOpen()}.");
				if (IsOpen)
				{
					Close();
					return;
				}
				if (flag && !UiState.VanillaMenuOpen())
				{
					Open();
				}
			}
			if (!IsOpen)
			{
				return;
			}
			if (!_typingBlock && VarkourInput.Down(VarkourConfig.CursorToggleKey))
			{
				SetCursorActive(!CursorActive);
			}
			SetTypingBlock(((Object)(object)_nameInput != (Object)null && _nameInput.isFocused) || ((Object)(object)_renameInput != (Object)null && _renameInput.isFocused));
			if (_dirty || _builtRevision != ClientCourses.Revision || _builtMode != current || _builtTab != _tab || _builtBoardCourse != _selectedBoardCourse)
			{
				Rebuild();
			}
			if ((Object)(object)_addSpotButton != (Object)null && current == VarkourMode.Editing)
			{
				bool flag2 = CourseEditor.CanAddCheckpointAtPlayer();
				if (((Selectable)_addSpotButton).interactable != flag2)
				{
					((Selectable)_addSpotButton).interactable = flag2;
				}
			}
		}

		public static void Open()
		{
			if (EnsureBuilt())
			{
				_panel.SetActive(true);
				_confirm.SetActive(false);
				SetCursorActive(active: true);
				_practiceToggle.SetIsOnWithoutNotify(RunController.Practice);
				_dirty = true;
				if (_tab == Tab.Leaderboards && _selectedBoardCourse != null)
				{
					VarkourNet.RequestLeaderboard(_selectedBoardCourse);
				}
			}
		}

		public static void Close()
		{
			if (!((Object)(object)_panel == (Object)null) && _panel.activeSelf)
			{
				_panel.SetActive(false);
				SetTypingBlock(block: false);
				SetCursorActive(active: false);
			}
		}

		private static void SetCursorActive(bool active)
		{
			if (CursorActive != active || !((Object)(object)_panelGroup != (Object)null))
			{
				CursorActive = active;
				if ((Object)(object)_panelGroup != (Object)null)
				{
					_panelGroup.interactable = active;
					_panelGroup.blocksRaycasts = active;
					_panelGroup.alpha = (active ? 1f : 0.55f);
				}
				if (!active)
				{
					SetTypingBlock(block: false);
				}
				UpdateCursorHint();
			}
		}

		private static void UpdateCursorHint()
		{
			if (!((Object)(object)_cursorHint == (Object)null))
			{
				string text = VarkourInput.KeyName(VarkourConfig.CursorToggleKey);
				_cursorHint.text = VarkourLocalization.T(CursorActive ? "varkour_hint_to_build" : "varkour_hint_to_click", text);
				if ((Object)(object)_focusButton != (Object)null && _focusButton.activeSelf != CursorActive)
				{
					_focusButton.SetActive(CursorActive);
				}
			}
		}

		private static void SetTypingBlock(bool block)
		{
			if (_typingBlock != block)
			{
				_typingBlock = block;
				GUIManager.BlockInput(block);
			}
		}

		private static bool EnsureBuilt()
		{
			//IL_004d: 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)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: 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_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: 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_01f5: 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_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Expected O, but got Unknown
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_0327: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0401: Unknown result type (might be due to invalid IL or missing references)
			//IL_0410: Unknown result type (might be due to invalid IL or missing references)
			//IL_041f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0444: Unknown result type (might be due to invalid IL or missing references)
			//IL_044e: Expected O, but got Unknown
			//IL_0492: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_052b: Unknown result type (might be due to invalid IL or missing references)
			//IL_053a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0549: Unknown result type (might be due to invalid IL or missing references)
			//IL_056e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0578: Expected O, but got Unknown
			//IL_0592: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05be: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f4: Expected O, but got Unknown
			if ((Object)(object)_panel != (Object)null)
			{
				return true;
			}
			GameObject customGUIFront = GUIManager.CustomGUIFront;
			if ((Object)(object)customGUIFront == (Object)null)
			{
				VarkourPlugin.Log.LogWarning((object)"Cannot open the Varkour window yet: Jötunn's CustomGUIFront is not available.");
				return false;
			}
			GUIManager instance = GUIManager.Instance;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			_panel = instance.CreateWoodpanel(customGUIFront.transform, val, val, Vector2.zero, 900f, 640f, true);
			((Object)_panel).name = "Varkour_Window";
			_title = instance.CreateText(VarkourLocalization.T("varkour_window_title"), _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -35f), instance.NorseBold, 32, instance.ValheimOrange, true, Color.black, 860f, 44f, false).GetComponent<Text>();
			_title.alignment = (TextAnchor)4;
			_panelGroup = _panel.GetComponent<CanvasGroup>() ?? _panel.AddComponent<CanvasGroup>();
			float left = -420f;
			left = TopButton(VarkourLocalization.T("varkour_tab_courses"), left, 170f, delegate
			{
				SetTab(Tab.Courses);
			});
			left = TopButton(VarkourLocalization.T("varkour_tab_leaderboards"), left, 180f, delegate
			{
				SetTab(Tab.Leaderboards);
			});
			left = TopButton(VarkourLocalization.T("varkour_tab_info"), left, 110f, delegate
			{
				SetTab(Tab.Info);
			});
			left += 36f;
			GameObject obj = instance.CreateToggle(_panel.transform, 28f, 28f);
			RectTransform val2 = (RectTransform)obj.transform;
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(0.5f, 1f);
			val2.anchorMax = val3;
			val2.anchorMin = val3;
			val2.anchoredPosition = new Vector2(left + 14f, -85f);
			_practiceToggle = obj.GetComponent<Toggle>();
			_practiceToggle.isOn = RunController.Practice;
			((UnityEvent<bool>)(object)_practiceToggle.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v)
			{
				RunController.Practice = v;
			});
			left += 38f;
			instance.CreateText(VarkourLocalization.T("varkour_practice"), _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(left + 95f, -85f), instance.AveriaSerifBold, 18, instance.ValheimBeige, true, Color.black, 190f, 30f, false).GetComponent<Text>().alignment = (TextAnchor)3;
			_newCourseRow = new GameObject("NewCourse", new Type[1] { typeof(RectTransform) });
			_newCourseRow.transform.SetParent(_panel.transform, false);
			RectTransform val4 = (RectTransform)_newCourseRow.transform;
			((Vector2)(ref val3))..ctor(0.5f, 1f);
			val4.anchorMax = val3;
			val4.anchorMin = val3;
			val4.anchoredPosition = new Vector2(0f, -130f);
			val4.sizeDelta = new Vector2(840f, 36f);
			_nameInput = instance.CreateInputField(_newCourseRow.transform, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(220f, 0f), (ContentType)0, VarkourLocalization.T("varkour_course_name_placeholder"), 18, 440f, 34f).GetComponent<InputField>();
			_nameInput.characterLimit = VarkourConfig.MaxCourseNameLength.Value;
			((UnityEvent)instance.CreateButton(VarkourLocalization.T("varkour_new_course"), _newCourseRow.transform, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-110f, 0f), 200f, 34f).GetComponent<Button>().onClick).AddListener(new UnityAction(OnNewCourse));
			_content = BuildScrollList(instance);
			float num = -207f;
			_focusButton = instance.CreateButton(VarkourLocalization.T("varkour_focus_game", VarkourInput.KeyName(VarkourConfig.CursorToggleKey)), _panel.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(num, 70f), 230f, 36f);
			ButtonClickedEvent onClick = _focusButton.GetComponent<Button>().onClick;
			object obj2 = <>c.<>9__61_4;
			if (obj2 == null)
			{
				UnityAction val5 = delegate
				{
					SetCursorActive(active: false);
				};
				<>c.<>9__61_4 = val5;
				obj2 = (object)val5;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj2);
			((UnityEvent)instance.CreateButton(VarkourLocalization.T("varkour_close", VarkourInput.KeyName(VarkourConfig.WindowKey)), _panel.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 70f), 160f, 36f).GetComponent<Button>().onClick).AddListener(new UnityAction(Close));
			_cursorHint = instance.CreateText(string.Empty, _panel.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 34f), instance.AveriaSerifBold, 16, instance.ValheimBeige, true, Color.black, 840f, 24f, false).GetComponent<Text>();
			_cursorHint.alignment = (TextAnchor)4;
			BuildConfirm(instance);
			_panel.SetActive(false);
			return true;
		}

		private static RectTransform BuildScrollList(GUIManager gui)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_0064: 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: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: 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_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Expected O, but got Unknown
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Expected O, but got Unknown
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("List", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(ScrollRect)
			});
			val.transform.SetParent(_panel.transform, false);
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			val2.pivot = new Vector2(0.5f, 0.5f);
			val2.offsetMin = new Vector2(30f, 100f);
			val2.offsetMax = new Vector2(-30f, -155f);
			((Graphic)val.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.3f);
			GameObject val3 = new GameObject("Viewport", new Type[2]
			{
				typeof(RectTransform),
				typeof(RectMask2D)
			});
			val3.transform.SetParent(val.transform, false);
			RectTransform val4 = (RectTransform)val3.transform;
			val4.anchorMin = Vector2.zero;
			val4.anchorMax = Vector2.one;
			val4.pivot = new Vector2(0f, 1f);
			val4.offsetMin = Vector2.zero;
			val4.offsetMax = new Vector2(-18f, 0f);
			GameObject val5 = new GameObject("Content", new Type[1] { typeof(RectTransform) });
			val5.transform.SetParent(val3.transform, false);
			RectTransform val6 = (RectTransform)val5.transform;
			val6.anchorMin = new Vector2(0f, 1f);
			val6.anchorMax = new Vector2(1f, 1f);
			val6.pivot = new Vector2(0.5f, 1f);
			val6.anchoredPosition = Vector2.zero;
			val6.sizeDelta = Vector2.zero;
			VerticalLayoutGroup obj = val5.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj).childAlignment = (TextAnchor)0;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 4f;
			((LayoutGroup)obj).padding = new RectOffset(8, 8, 8, 8);
			ContentSizeFitter obj2 = val5.AddComponent<ContentSizeFitter>();
			obj2.horizontalFit = (FitMode)0;
			obj2.verticalFit = (FitMode)2;
			GameObject obj3 = DefaultControls.CreateScrollbar(gui.ValheimControlResources);
			obj3.transform.SetParent(val.transform, false);
			RectTransform val7 = (RectTransform)obj3.transform;
			val7.anchorMin = new Vector2(1f, 0f);
			val7.anchorMax = new Vector2(1f, 1f);
			val7.pivot = new Vector2(1f, 0.5f);
			val7.sizeDelta = new Vector2(14f, 0f);
			val7.anchoredPosition = Vector2.zero;
			Scrollbar component = obj3.GetComponent<Scrollbar>();
			component.direction = (Direction)2;
			gui.ApplyScrollbarStyle(component);
			ScrollRect component2 = val.GetComponent<ScrollRect>();
			component2.viewport = val4;
			component2.content = val6;
			component2.horizontal = false;
			component2.vertical = true;
			component2.movementType = (MovementType)2;
			component2.scrollSensitivity = 30f;
			component2.verticalScrollbar = component;
			component2.verticalScrollbarVisibility = (ScrollbarVisibility)0;
			return val6;
		}

		private static float TopButton(string text, float left, float width, Action onClick)
		{
			//IL_0027: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			((UnityEvent)GUIManager.Instance.CreateButton(text, _panel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(left + width / 2f, -85f), width, 36f).GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				onClick();
			});
			return left + width + 12f;
		}

		private static void BuildConfirm(GUIManager gui)
		{
			//IL_001c: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_0119: 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_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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_00ff: Expected O, but got Unknown
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Expected O, but got Unknown
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			_confirm = gui.CreateWoodpanel(_panel.transform, val, val, Vector2.zero, 520f, 220f, false);
			((Object)_confirm).name = "Confirm";
			_confirmText = gui.CreateText(string.Empty, _confirm.transform, val, val, new Vector2(0f, 30f), gui.AveriaSerifBold, 18, gui.ValheimBeige, true, Color.black, 460f, 110f, false).GetComponent<Text>();
			_confirmText.alignment = (TextAnchor)4;
			ButtonClickedEvent onClick = gui.CreateButton(VarkourLocalization.T("varkour_yes"), _confirm.transform, val, val, new Vector2(-90f, -60f), 150f, 36f).GetComponent<Button>().onClick;
			object obj = <>c.<>9__64_0;
			if (obj == null)
			{
				UnityAction val2 = delegate
				{
					_confirm.SetActive(false);
					Action confirmAction = _confirmAction;
					_confirmAction = null;
					confirmAction?.Invoke();
				};
				<>c.<>9__64_0 = val2;
				obj = (object)val2;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
			ButtonClickedEvent onClick2 = gui.CreateButton(VarkourLocalization.T("varkour_no"), _confirm.transform, val, val, new Vector2(90f, -60f), 150f, 36f).GetComponent<Button>().onClick;
			object obj2 = <>c.<>9__64_1;
			if (obj2 == null)
			{
				UnityAction val3 = delegate
				{
					_confirm.SetActive(false);
					_confirmAction = null;
				};
				<>c.<>9__64_1 = val3;
				obj2 = (object)val3;
			}
			((UnityEvent)onClick2).AddListener((UnityAction)obj2);
			_confirm.SetActive(false);
		}

		private static void Confirm(string text, Action action)
		{
			_confirmText.text = text;
			_confirmAction = action;
			_confirm.SetActive(true);
			_confirm.transform.SetAsLastSibling();
		}

		private static void SetTab(Tab tab)
		{
			_tab = tab;
			if (tab == Tab.Leaderboards && _selectedBoardCourse != null)
			{
				VarkourNet.RequestLeaderboard(_selectedBoardCourse);
			}
			_dirty = true;
		}

		private static void Rebuild()
		{
			_dirty = false;
			_builtRevision = ClientCourses.Revision;
			_builtMode = ModeMachine.Current;
			_builtTab = _tab;
			_builtBoardCourse = _selectedBoardCourse;
			int num;
			object renameTextInFlight;
			if ((Object)(object)_renameInput != (Object)null && _renameCourse != null)
			{
				num = ((_renameCourse == CourseEditor.Open) ? 1 : 0);
				if (num != 0)
				{
					renameTextInFlight = _renameInput.text;
					goto IL_0061;
				}
			}
			else
			{
				num = 0;
			}
			renameTextInFlight = null;
			goto IL_0061;
			IL_0061:
			_renameTextInFlight = (string)renameTextInFlight;
			_renameFocusInFlight = num != 0 && _renameInput.isFocused;
			for (int num2 = ((Transform)_content).childCount - 1; num2 >= 0; num2--)
			{
				Object.Destroy((Object)(object)((Component)((Transform)_content).GetChild(num2)).gameObject);
			}
			_addSpotButton = null;
			_renameInput = null;
			_renameCourse = null;
			bool flag = ModeMachine.Current == VarkourMode.Editing;
			_newCourseRow.SetActive(_tab == Tab.Courses && !flag);
			UpdateCursorHint();
			if (_tab == Tab.Info)
			{
				BuildInfo();
			}
			else if (_tab == Tab.Courses)
			{
				if (flag)
				{
					BuildZoneList();
				}
				else
				{
					BuildCourseList();
				}
			}
			else if (_selectedBoardCourse != null && ClientCourses.GetPublished(_selectedBoardCourse) != null)
			{
				BuildLeaderboard(ClientCourses.GetPublished(_selectedBoardCourse));
			}
			else
			{
				_selectedBoardCourse = null;
				_builtBoardCourse = null;
				BuildBoardCourseList();
			}
		}

		private static void BuildCourseList()
		{
			if (!ClientCourses.HasWorld)
			{
				Label(VarkourLocalization.T("varkour_loading"));
				return;
			}
			long localPlayerId = ClientCourses.LocalPlayerId;
			int num = 0;
			ClientCourses.GetMyDrafts(MyDrafts);
			foreach (Course myDraft in MyDrafts)
			{
				num++;
				Course course = myDraft;
				RectTransform row = Row();
				RowText(row, course.Name + "   <color=#A0A0A0>" + VarkourLocalization.T("varkour_draft") + " · " + ZoneSummary(course) + "</color>");
				VisibilityButton(row, course);
				RowButton(row, VarkourLocalization.T("varkour_edit"), 110f, delegate
				{
					if (CourseEditor.Begin(course))
					{
						_tab = Tab.Courses;
					}
				});
				RowButton(row, VarkourLocalization.T("varkour_delete"), 110f, delegate
				{
					Confirm(VarkourLocalization.T("varkour_confirm_delete", course.Name), delegate
					{
						ClientCourses.DeleteDraft(course.Id);
					});
				});
			}
			foreach (Course item in ClientCourses.Published)
			{
				if (item.AuthorId != localPlayerId)
				{
					continue;
				}
				num++;
				Course course2 = item;
				RectTransform row2 = Row();
				RowText(row2, course2.Name + "   <color=#80C0FF>" + VarkourLocalization.T("varkour_published") + " · " + ZoneSummary(course2) + "</color>");
				VisibilityButton(row2, course2);
				RowButton(row2, VarkourLocalization.T("varkour_edit"), 110f, delegate
				{
					Confirm(VarkourLocalization.T("varkour_confirm_unpublish", course2.Name), delegate
					{
						CourseEditor.BeginFromPublished(course2);
						_tab = Tab.Courses;
					});
				});
				RowButton(row2, VarkourLocalization.T("varkour_delete"), 110f, delegate
				{
					Confirm(VarkourLocalization.T("varkour_confirm_delete", course2.Name), delegate
					{
						VarkourNet.SendDelete(course2.Id);
					});
				});
			}
			if (num == 0)
			{
				Label(VarkourLocalization.T("varkour_no_courses"));
			}
		}

		private static void BuildZoneList()
		{
			//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)
			Course open = CourseEditor.Open;
			if (open == null)
			{
				return;
			}
			RectTransform val = Row();
			RowFixedText(val, "<b>" + VarkourLocalization.T("varkour_editing") + "</b>", 170f);
			GameObject obj = GUIManager.Instance.CreateInputField((Transform)(object)val, Vector2.zero, Vector2.zero, Vector2.zero, (ContentType)0, VarkourLocalization.T("varkour_course_name_placeholder"), 18, 100f, 34f);
			LayoutElement obj2 = obj.AddComponent<LayoutElement>();
			obj2.minWidth = 200f;
			obj2.preferredWidth = 200f;
			obj2.flexibleWidth = 1f;
			obj2.preferredHeight = 34f;
			_renameInput = obj.GetComponent<InputField>();
			_renameInput.characterLimit = VarkourConfig.MaxCourseNameLength.Value;
			_renameInput.text = _renameTextInFlight ?? open.Name;
			_renameCourse = open;
			if (_renameFocusInFlight)
			{
				_renameInput.ActivateInputField();
			}
			_renameTextInFlight = null;
			_renameFocusInFlight = false;
			((UnityEvent<string>)(object)_renameInput.onEndEdit).AddListener((UnityAction<string>)delegate
			{
				ApplyRename();
			});
			RowButton(val, VarkourLocalization.T("varkour_close_editor"), 180f, delegate
			{
				ApplyRename();
				CourseEditor.Close();
				_dirty = true;
			});
			Label("<color=#A0A0A0>" + VarkourLocalization.T("varkour_zone_hint", RemoveKeyName()) + "</color>");
			if (!open.IsRunnable)
			{
				Label("<color=#FFB060>" + VarkourLocalization.T("varkour_course_invalid") + "</color>");
			}
			for (int num = 0; num < open.Zones.Count; num++)
			{
				int index = num;
				Zone zone = open.Zones[num];
				RectTransform row = Row();
				string text = ((zone.Type == ZoneType.Checkpoint) ? VarkourLocalization.T("varkour_spot", open.CheckpointNumberAt(num)) : CourseEditor.LabelFor(open, num));
				if (zone == CourseEditor.SelectedZone)
				{
					text = "<color=#FFE040><b>" + text + "</b></color>";
				}
				RowText(row, text, delegate
				{
					CourseEditor.SelectAt(index);
				});
				if (zone.Type == ZoneType.Checkpoint)
				{
					RowButton(row, VarkourLocalization.T("varkour_up"), 34f, delegate
					{
						CourseEditor.MoveCheckpoint(index, -1);
					}, CourseEditor.CanMoveCheckpoint(open, index, -1));
					RowButton(row, VarkourLocalization.T("varkour_down"), 34f, delegate
					{
						CourseEditor.MoveCheckpoint(index, 1);
					}, CourseEditor.CanMoveCheckpoint(open, index, 1));
				}
				else
				{
					Spacer(row, 74f);
				}
				RowButton(row, "-", 34f, delegate
				{
					CourseEditor.AdjustRadius(index, 0f - VarkourConfig.ZoneRadiusStep.Value);
				});
				RowFixedText(row, zone.Radius.ToString("0.0") + " m", 64f);
				RowButton(row, "+", 34f, delegate
				{
					CourseEditor.AdjustRadius(index, VarkourConfig.ZoneRadiusStep.Value);
				});
				RowButton(row, VarkourLocalization.T("varkour_zone_to_player"), 196f, delegate
				{
					CourseEditor.MoveToPlayer(index);
				});
				RowButton(row, VarkourLocalization.T("varkour_delete"), 80f, delegate
				{
					CourseEditor.RemoveAt(index);
				});
			}
			_addSpotButton = RowButton(Row(), VarkourLocalization.T("varkour_add_spot_here"), 320f, CourseEditor.AddCheckpointAtPlayer, CourseEditor.CanAddCheckpointAtPlayer());
		}

		private static void BuildInfo()
		{
			Label("<b>" + VarkourLocalization.T("varkour_info_keys") + "</b>");
			InfoRow(VarkourInput.KeyName(VarkourConfig.WindowKey), "varkour_info_window");
			InfoRow(VarkourInput.KeyName(VarkourConfig.CursorToggleKey), "varkour_info_cursor");
			InfoRow(VarkourInput.KeyName(VarkourConfig.RestartKey), "varkour_info_restart");
			InfoRow(VarkourInput.KeyName(VarkourConfig.CancelKey), "varkour_info_cancel");
			InfoRow(VarkourInput.KeyName(VarkourConfig.PracticeRespawnKey), "varkour_info_practice");
			InfoRow(VarkourLocalization.T("varkour_info_rmb"), "varkour_info_menu");
			InfoRow(VarkourLocalization.T("varkour_info_m1"), "varkour_info_place");
			InfoRow(VarkourLocalization.T("varkour_info_shift_scroll"), "varkour_info_size");
			InfoRow(RemoveKeyName(), "varkour_info_remove");
			Label(string.Empty);
			Label("<b>" + VarkourLocalization.T("varkour_info_buff") + "</b>");
			Label(VarkourLocalization.T("varkour_info_buff_desc"));
			InfoSection("varkour_info_build", 3);
			InfoSection("varkour_info_publish", 3);
			InfoSection("varkour_info_run", 3);
		}

		private static void InfoSection(string token, int lines)
		{
			Label(string.Empty);
			Label("<b>" + VarkourLocalization.T(token) + "</b>");
			for (int i = 1; i <= lines; i++)
			{
				Label(VarkourLocalization.T(token + i));
			}
		}

		private static void InfoRow(string key, string token)
		{
			RectTransform row = Row();
			RowFixedText(row, "<color=#FFE040>" + key + "</color>", 170f);
			RowText(row, VarkourLocalization.T(token));
		}

		private static void BuildBoardCourseList()
		{
			IReadOnlyList<Course> published = ClientCourses.Published;
			if (published.Count == 0)
			{
				Label(VarkourLocalization.T(ClientCourses.HasWorld ? "varkour_no_published" : "varkour_loading"));
				return;
			}
			foreach (Course item in published)
			{
				Course course = item;
				RectTransform row = Row();
				RowText(row, course.Name + "   <color=#A0A0A0>" + CourseStats(course) + "</color>");
				VisibilityButton(row, course);
				RowButton(row, VarkourLocalization.T("varkour_select"), 110f, delegate
				{
					_selectedBoardCourse = course.Id;
					VarkourNet.RequestLeaderboard(course.Id);
				});
			}
		}

		private static void BuildLeaderboard(Course course)
		{
			RectTransform row = Row();
			RowButton(row, "<", 44f, delegate
			{
				_selectedBoardCourse = null;
			});
			RowText(row, "<b>" + course.Name + "</b>   <color=#A0A0A0>" + CourseStats(course) + "</color>");
			RowButton(row, VarkourLocalization.T("varkour_show_on_map"), 170f, delegate
			{
				ShowOnMap(course);
			});
			if (course.AuthorId == ClientCourses.LocalPlayerId || ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.LocalPlayerIsAdminOrHost()))
			{
				RowButton(row, VarkourLocalization.T("varkour_delete"), 100f, delegate
				{
					Confirm(VarkourLocalization.T("varkour_confirm_delete", course.Name), delegate
					{
						VarkourNet.SendDelete(course.Id);
						_selectedBoardCourse = null;
					});
				});
			}
			LeaderboardView leaderboard = ClientCourses.GetLeaderboard(course.Id);
			if (leaderboard == null)
			{
				Label(VarkourLocalization.T("varkour_loading"));
				return;
			}
			if (leaderboard.Top.Count == 0)
			{
				Label(VarkourLocalization.T("varkour_no_times"));
			}
			for (int num = 0; num < leaderboard.Top.Count; num++)
			{
				RunRecord runRecord = leaderboard.Top[num];
				RectTransform row2 = Row();
				string text = "#" + (num + 1) + "   " + runRecord.PlayerName + "   " + VarkourLocalization.FormatTime(runRecord.TimeMs);
				if (runRecord.PlayerId == ClientCourses.LocalPlayerId)
				{
					text = "<color=#FFE040>" + text + "</color>";
				}
				RowText(row2, text);
			}
			if (leaderboard.Own != null && leaderboard.OwnRank > leaderboard.Top.Count)
			{
				Label(VarkourLocalization.T("varkour_your_best", leaderboard.OwnRank, VarkourLocalization.FormatTime(leaderboard.Own.TimeMs)));
			}
		}

		private static void ShowOnMap(Course course)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			Zone start = course.Start;
			if (start != null && !((Object)(object)Minimap.instance == (Object)null))
			{
				Close();
				Minimap.instance.ShowPointOnMap(start.Position);
			}
		}

		private static string RemoveKeyName()
		{
			string text = ((Localization.instance != null) ? Localization.instance.GetBoundKeyString("Remove", true) : null);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return "Remove";
		}

		private static string ZoneSummary(Course c)
		{
			return c.CheckpointCount + " checkpoint(s)" + (c.IsRunnable ? string.Empty : " · !");
		}

		private static string CourseStats(Course c)
		{
			return VarkourLocalization.T("varkour_by_author", c.AuthorName) + " · " + VarkourLocalization.T("varkour_runs", c.RunCount);
		}

		private static void OnNewCourse()
		{
			string text = CourseName.Clean(_nameInput.text, VarkourConfig.MaxCourseNameLength.Value);
			if (text.Length == 0)
			{
				Notify.Center(VarkourLocalization.T("varkour_msg_name_required"));
				return;
			}
			if (!ClientCourses.HasWorld)
			{
				Notify.Center(VarkourLocalization.T("varkour_loading"));
				return;
			}
			Course draft = ClientCourses.CreateDraft(text);
			_nameInput.text = string.Empty;
			CourseEditor.Begin(draft);
			_dirty = true;
		}

		private static RectTransform Row()
		{
			//IL_0018: 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_002e: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			GameObject val = new GameObject("Row", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent((Transform)(object)_content, false);
			HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 6f;
			val.AddComponent<LayoutElement>().minHeight = 34f;
			return (RectTransform)val.transform;
		}

		private static void RowText(RectTransform row, string text, Action onClick = null)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_003a: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			GameObject val = GUIManager.Instance.CreateText(text, (Transform)(object)row, Vector2.zero, Vector2.one, Vector2.zero, GUIManager.Instance.AveriaSerifBold, 18, GUIManager.Instance.ValheimBeige, true, Color.black, 100f, 34f, false);
			Text component = val.GetComponent<Text>();
			component.alignment = (TextAnchor)3;
			component.supportRichText = true;
			if (onClick != null)
			{
				((Graphic)component).raycastTarget = true;
				Button obj = val.AddComponent<Button>();
				((Selectable)obj).targetGraphic = (Graphic)(object)component;
				((Selectable)obj).transition = (Transition)0;
				((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
				{
					onClick();
					_dirty = true;
				});
			}
			component.horizontalOverflow = (HorizontalWrapMode)0;
			component.verticalOverflow = (VerticalWrapMode)1;
			((RectTransform)val.transform).pivot = new Vector2(0f, 0.5f);
			LayoutElement obj2 = val.AddComponent<LayoutElement>();
			obj2.minWidth = 80f;
			obj2.preferredWidth = 80f;
			obj2.flexibleWidth = 1f;
		}

		private static Button RowButton(RectTransform row, string text, float width, Action onClick, bool enabled = true)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0070: Expected O, but got Unknown
			GameObject obj = GUIManager.Instance.CreateButton(text, (Transform)(object)row, Vector2.zero, Vector2.zero, Vector2.zero, width, 34f);
			LayoutElement obj2 = obj.AddComponent<LayoutElement>();
			obj2.preferredWidth = width;
			obj2.minWidth = width;
			obj2.preferredHeight = 34f;
			Button component = obj.GetComponent<Button>();
			((Selectable)component).interactable = enabled;
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				try
				{
					onClick();
				}
				catch (Exception arg)
				{
					VarkourPlugin.Log.LogError((object)$"Window action failed: {arg}");
				}
				_dirty = true;
			});
			return component;
		}

		private static void RowFixedText(RectTransform row, string text, float width)
		{
			//IL_0007: 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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GUIManager.Instance.CreateText(text, (Transform)(object)row, Vector2.zero, Vector2.one, Vector2.zero, GUIManager.Instance.AveriaSerifBold, 18, GUIManager.Instance.ValheimBeige, true, Color.black, width, 34f, false);
			obj.GetComponent<Text>().alignment = (TextAnchor)4;
			LayoutElement obj2 = obj.AddComponent<LayoutElement>();
			obj2.preferredWidth = width;
			obj2.minWidth = width;
			obj2.preferredHeight = 34f;
		}

		private static void VisibilityButton(RectTransform row, Course course)
		{
			bool hidden = ClientCourses.IsHidden(course.Id);
			RowButton(row, VarkourLocalization.T(hidden ? "varkour_show" : "varkour_hide"), 80f, delegate
			{
				ClientCourses.SetHidden(course.Id, !hidden);
			});
		}

		private static void Spacer(RectTransform row, float width)
		{
			//IL_0018: 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)
			GameObject val = new GameObject("Spacer", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent((Transform)(object)row, false);
			LayoutElement obj = val.AddComponent<LayoutElement>();
			obj.preferredWidth = width;
			obj.minWidth = width;
			obj.preferredHeight = 34f;
		}

		private static void Label(string text)
		{
			RowText(Row(), text);
		}
	}
}
namespace Varkour.Runs
{
	internal static class RunController
	{
		private enum Phase
		{
			AwaitExit,
			Timing
		}

		private const float RuleCheckInterval = 0.5f;

		private const float HudInterval = 0.05f;

		private const float TeleportJumpDistance = 40f;

		private const float LeaderboardRequestInterval = 30f;

		private static readonly List<Course> Visible = new List<Course>();

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

		private static readonly StringBuilder Sb = new StringBuilder(256);

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

		private static Course _candidate;

		private static float _stillTime;

		private static int _lastCountShown = -1;

		private static string _idleReason;

		private static float _nextIdleRuleCheck;

		private static Phase _phase;

		private static double _goTime;

		private static double _timerStart;

		private static int _lastHitIndex;

		private static string _unrankedReason;

		private static float _nextRuleCheck;

		private static Vector3 _lastPos;

		private static int _runCounter;

		private static int _courseRevisionSeen;

		private static float _nextHud;

		private static Course _lastCourse;

		private const float CheckpointGrace = 0.3f;

		public static bool Practice { get; set; }

		public static Course ActiveCourse { get; private set; }

		public static int NextZoneIndex { get; private set; } = -1;

		public static bool AwaitingExit
		{
			get
			{
				if (ModeMachine.Current == VarkourMode.Running)
				{
					return _phase == Phase.AwaitExit;
				}
				return false;
			}
		}

		public static int VisualStep
		{
			get
			{
				if (ModeMachine.Current != VarkourMode.Running)
				{
					return -1;
				}
				return _runCounter * 1000 + NextZoneIndex + (AwaitingExit ? 500 : 0);
			}
		}

		private static double Clock => Time.unscaledTimeAsDouble;

		public static void Init()
		{
			ModeMachine.Changed += OnModeChanged;
		}

		private static void OnModeChanged(VarkourMode previous, VarkourMode next)
		{
			if (previous == VarkourMode.Running && next == VarkourMode.Off && ActiveCourse != null)
			{
				Player localPlayer = Player.m_localPlayer;
				Notify.Center(VarkourLocalization.T(((Object)(object)localPlayer != (Object)null && ((Character)localPlayer).IsDead()) ? "varkour_msg_cancel_death" : "varkour_msg_cancel_unequip"));
				ClearRun();
			}
			if (next != VarkourMode.Idle)
			{
				ResetCountdown();
			}
			if (next == VarkourMode.Off || next == VarkourMode.Editing)
			{
				RunHud.SetMain(null);
			}
			if (next == VarkourMode.Off)
			{
				RunHud.HideResults();
			}
		}

		public static void Tick()
		{
			ModTeleport.ClearIfDone();
			RunHud.Tick();
			switch (ModeMachine.Current)
			{
			case VarkourMode.Idle:
				HandleKeys();
				if (ModeMachine.Current == VarkourMode.Idle)
				{
					TickIdle();
				}
				break;
			case VarkourMode.Running:
				HandleKeys();
				if (ModeMachine.Current == VarkourMode.Running)
				{
					TickRunning();
				}
				break;
			}
		}

		private static void HandleKeys()
		{
			if (UiState.WorldInputBlocked())
			{
				return;
			}
			if (VarkourInput.Down(VarkourConfig.CancelKey))
			{
				if (ModeMachine.Current == VarkourMode.Running)
				{
					Cancel("varkour_msg_cancelled");
				}
				else
				{
					ResetCountdown();
				}
			}
			else if (VarkourInput.Down(VarkourConfig.RestartKey))
			{
				Restart();
			}
			else if (VarkourInput.Down(VarkourConfig.PracticeRespawnKey))
			{
				PracticeRespawn();
			}
		}

		private static void Restart()
		{
			//IL_004e: 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)
			Course course = ((ModeMachine.Current == VarkourMode.Running) ? ActiveCourse : (_candidate ?? _lastCourse));
			course = Refresh(course);
			if (course != null && course.Start != null)
			{
				if (ModeMachine.Current == VarkourMode.Running)
				{
					ClearRun();
					ModeMachine.ReturnToIdle();
				}
				ResetCountdown();
				ModTeleport.To(course.Start.Position, FacingFrom(course, 0));
			}
		}

		private static void PracticeRespawn()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (Practice && ModeMachine.Current == VarkourMode.Running && ActiveCourse != null)
			{
				int index = ((_phase == Phase.Timing) ? Mathf.Clamp(_lastHitIndex, 0, ActiveCourse.Zones.Count - 1) : 0);
				ModTeleport.To(ActiveCourse.Zones[index].Position, FacingFrom(ActiveCourse, index));
			}
		}

		private static Quaternion FacingFrom(Course course, int index)
		{
			//IL_001e: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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)
			if (index + 1 < course.Zones.Count)
			{
				Vector3 val = course.Zones[index + 1].Position - course.Zones[index].Position;
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude > 0.01f)
				{
					return Quaternion.LookRotation(((Vector3)(ref val)).normalized);
				}
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer != (Object)null))
			{
				return Quaternion.identity;
			}
			return ((Component)localPlayer).transform.rotation;
		}

		private static void TickIdle()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || UiState.WorldInputBlocked())
			{
				ResetCountdown();
				RunHud.SetMain(null);
				return;
			}
			Course course = FindStartZoneCourse(((Component)localPlayer).transform.position);
			if (course != _candidate)
			{
				ResetCountdown();
				_candidate = course;
			}
			if (course == null)
			{
				RunHud.SetMain(null);
				return;
			}
			if (!course.IsRunnable)
			{
				RunHud.SetMain(course.Name + "\n" + VarkourLocalization.T("varkour_course_invalid"));
				return;
			}
			MaybeRequestLeaderboard(course);
			int num;
			if (((Character)localPlayer).IsOnGround())
			{
				num = ((HorizontalSpeed(localPlayer) < VarkourConfig.StillSpeedThreshold.Value) ? 1 : 0);
				if (num != 0)
				{
					_stillTime += Time.deltaTime;
					goto IL_00c0;
				}
			}
			else
			{
				num = 0;
			}
			_stillTime = 0f;
			_lastCountShown = -1;
			goto IL_00c0;
			IL_00c0:
			int value = VarkourConfig.CountdownSeconds.Value;
			string text = null;
			if (num != 0)
			{
				int num2 = Mathf.CeilToInt((float)value - _stillTime);
				if (num2 != _lastCountShown && num2 > 0)
				{
					_lastCountShown = num2;
					RunFeedback.Tick();
				}
				if (_stillTime >= (float)value)
				{
					StartRun(course);
					return;
				}
				text = VarkourLocalization.T("varkour_hud_ready");
			}
			if (!(Time.time < _nextHud))
			{
				if (Time.time >= _nextIdleRuleCheck)
				{
					_nextIdleRuleCheck = Time.time + 0.5f;
					_idleReason = RunRules.GetUnrankedReason(localPlayer);
				}
				_nextHud = Time.time + 0.05f;
				Sb.Length = 0;
				Sb.Append(VarkourLocalization.T("varkour_hud_course", course.Name));
				if (ClientCourses.IsDraft(course))
				{
					Sb.Append("  (").Append(VarkourLocalization.T("varkour_draft")).Append(')');
				}
				Sb.Append('\n');
				if (text != null)
				{
					Sb.Append("<size=40>").Append(text).Append("</size>");
				}
				else
				{
					Sb.Append(VarkourLocalization.T("varkour_hud_stand_still"));
				}
				Sb.Append('\n').Append(VarkourLocalization.T("varkour_hud_next", 0, course.Zones.Count - 1));
				Sb.Append("   ").Append(PbText(course)).Append('\n')
					.Append(RecordText(course));
				if (_idleReason != null)
				{
					Sb.Append("\n<color=#FFB060>").Append(VarkourLocalization.T("varkour_hud_unranked", _idleReason)).Append("</color>");
				}
				RunHud.SetMain(Sb.ToString());
			}
		}

		private static Course FindStartZoneCourse(Vector3 pos)
		{
			//IL_0035: 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)
			ClientCourses.GetShown(Visible);
			Course result = null;
			float num = float.MaxValue;
			foreach (Course item in Visible)
			{
				Zone start = item.Start;
				if (start != null && InZone(start, pos))
				{
					float num2 = HorizontalDistance(start.Position, pos);
					if (num2 < num)
					{
						num = num2;
						result = item;
					}
				}
			}
			return result;
		}

		private static void ResetCountdown()
		{
			_candidate = null;
			_stillTime = 0f;
			_lastCountShown = -1;
		}

		private static void MaybeRequestLeaderboard(Course course)
		{
			if (!ClientCourses.IsDraft(course) && ClientCourses.GetLeaderboard(course.Id) == null && (!LastLeaderboardRequest.TryGetValue(course.Id, out var value) || !(Time.time - value < 30f)))
			{
				LastLeaderboardRequest[course.Id] = Time.time;
				VarkourNet.RequestLeaderboard(course.Id);
			}
		}

		private static void StartRun(Course course)
		{
			//IL_008d: 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)
			if (ModeMachine.TryEnterRunning())
			{
				Player localPlayer = Player.m_localPlayer;
				ResetCountdown();
				RunHud.HideResults();
				ActiveCourse = course;
				_lastCourse = course;
				_phase = Phase.AwaitExit;
				_goTime = Clock;
				_timerStart = 0.0;
				_lastHitIndex = 0;
				NextZoneIndex = 1;
				Splits.Clear();
				_runCounter++;
				_courseRevisionSeen = ClientCourses.Revision;
				_unrankedReason = RunRules.GetUnrankedReason(localPlayer);
				_nextRuleCheck = Time.time + 0.5f;
				_lastPos = ((Component)localPlayer).transform.position;
				_nextHud = 0f;
				RunFeedback.Tick();
			}
		}

		private static void TickRunning()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_0049: 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_005b: 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_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			Course activeCourse = ActiveCourse;
			if ((Object)(object)localPlayer == (Object)null || activeCourse == null)
			{
				Cancel(null);
				return;
			}
			if (((Character)localPlayer).IsDead())
			{
				Cancel("varkour_msg_cancel_death");
				return;
			}
			Vector3 position = ((Component)localPlayer).transform.position;
			Vector3 val = position - _lastPos;
			bool flag = ((Vector3)(ref val)).sqrMagnitude > 1600f;
			_lastPos = position;
			if (!ModTeleport.InProgress && (((Character)localPlayer).IsTeleporting() || flag))
			{
				Cancel("varkour_msg_cancel_teleport");
				return;
			}
			if (Clock - _goTime > (double)VarkourConfig.RunTimeoutSeconds.Value)
			{
				Cancel("varkour_msg_cancel_timeout");
				return;
			}
			if (_courseRevisionSeen != ClientCourses.Revision)
			{
				_courseRevisionSeen = ClientCourses.Revision;
				Course course = Refresh(activeCourse);
				if (course == null || course.Version != activeCourse.Version)
				{
					Cancel("varkour_msg_cancelled");
					return;
				}
			}
			if (Time.time >= _nextRuleCheck)
			{
				_nextRuleCheck = Time.time + 0.5f;
				if (_unrankedReason == null)
				{
					_unrankedReason = RunRules.GetUnrankedReason(localPlayer);
				}
			}
			if (_phase == Phase.AwaitExit)
			{
				if (!InZone(activeCourse.Start, position))
				{
					_phase = Phase.Timing;
					_timerStart = Clock;
					RunFeedback.Go();
					Notify.Center(VarkourLocalization.T("varkour_hud_go"));
				}
			}
			else if (!ModTeleport.InProgress)
			{
				Zone zone = activeCourse.Zones[NextZoneIndex];
				if (InZone(zone, position))
				{
					long num = ElapsedMs();
					Splits.Add(num);
					_lastHitIndex = NextZoneIndex;
					if (zone.Type == ZoneType.End)
					{
						Finish(activeCourse, num);
						return;
					}
					NextZoneIndex++;
					RunFeedback.ZoneHit(zone.Position);
				}
			}
			UpdateRunHud(activeCourse);
		}

		private static long ElapsedMs()
		{
			if (_phase != Phase.Timing)
			{
				return 0L;
			}
			return (long)((Clock - _timerStart) * 1000.0);
		}

		private static void UpdateRunHud(Course course)
		{
			if (!(Time.time < _nextHud))
			{
				_nextHud = Time.time + 0.05f;
				Sb.Length = 0;
				Sb.Append(VarkourLocalization.T("varkour_hud_course", course.Name)).Append('\n');
				if (_phase == Phase.AwaitExit)
				{
					Sb.Append("<size=40>").Append(VarkourLocalization.T("varkour_hud_set")).Append("</size>");
				}
				else
				{
					Sb.Append("<size=34>").Append(VarkourLocalization.FormatTime(ElapsedMs())).Append("</size>");
				}
				int num = course.Zones.Count - 1;
				int num2 = NextZoneIndex - 1;
				Sb.Append('\n').Append(VarkourLocalization.T("varkour_hud_next", num2, num));
				Sb.Append("   ").Append(PbText(course)).Append('\n')
					.Append(RecordText(course));
				if (_unrankedReason != null)
				{
					Sb.Append("\n<color=#FFB060>").Append(VarkourLocalization.T("varkour_hud_unranked", _unrankedReason)).Append("</color>");
				}
				Sb.Append("\n<size=16>").Append(VarkourLocalization.T("varkour_hud_keys", VarkourInput.KeyName(VarkourConfig.RestartKey), VarkourInput.KeyName(VarkourConfig.CancelKey)));
				if (Practice)
				{
					Sb.Append("   ").Append(VarkourLocalization.T("varkour_hud_practice_key", VarkourInput.KeyName(VarkourConfig.PracticeRespawnKey)));
				}
				Sb.Append("</size>");
				RunHud.SetMain(Sb.ToString());
			}
		}

		private static void Finish(Course course, long totalMs)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			string text = _unrankedReason ?? RunRules.GetUnrankedReason(Player.m_localPlayer);
			List<long> splits = new List<long>(Splits);
			long timeMs;
			List<long> splits2;
			bool flag = ClientCourses.TryGetPersonalBest(course, out timeMs, out splits2);
			bool num = ClientCourses.IsDraft(course);
			RunFeedback.Finish(((Component)Player.m_localPlayer).transform.position);
			ShowResults(course, totalMs, splits, flag ? splits2 : null, text);
			ClearRun();
			ModeMachine.ReturnToIdle();
			RunHud.SetMain(null);
			if (num)
			{
				ClientCourses.RecordDraftRun(course, totalMs);
				if (text == null && course.AuthorId == ClientCourses.LocalPlayerId)
				{
					Notify.Center(VarkourLocalization.T("varkour_msg_publishing", course.Name));
					VarkourNet.SendPublish(course, totalMs, splits);
				}
				else
				{
					string text2 = text ?? "not the author";
					VarkourPlugin.Log.LogInfo((object)("Draft '" + course.Name + "' finished but not published: " + text2));
					Notify.Center(VarkourLocalization.T("varkour_msg_draft_not_published", text2));
				}
				ClientCourses.Changed();
			}
			else if (text == null)
			{
				VarkourNet.SendSubmitRun(course, totalMs, splits);
			}
		}

		private static void ShowResults(Course course, long totalMs, List<long> splits, List<long> pbSplits, string reason)
		{
			Sb.Length = 0;
			Sb.Append("<size=22>").Append(course.Name).Append("</size>\n");
			Sb.Append(CourseRecordText(course)).Append('\n');
			Sb.Append(VarkourLocalization.T("varkour_hud_finished", VarkourLocalization.FormatTime(totalMs)));
			if (pbSplits != null && pbSplits.Count == splits.Count)
			{
				Sb.Append("  ").Append(VarkourLocalization.FormatDelta(totalMs - pbSplits[pbSplits.Count - 1]));
			}
			Sb.Append('\n');
			if (reason != null)
			{
				Sb.Append("<color=#FFB060>").Append(VarkourLocalization.T("varkour_hud_unranked", reason)).Append("</color>\n");
			}
			for (int i = 0; i < splits.Count; i++)
			{
				int index = i + 1;
				string text = ((course.Zones[index].Type == ZoneType.End) ? VarkourLocalization.T("varkour_label_end") : CourseEditor.CheckpointLabel(course.CheckpointNumberAt(index)));
				Sb.Append(VarkourLocalization.T("varkour_hud_split", text, VarkourLocalization.FormatTime(splits[i])));
				if (pbSplits != null && pbSplits.Count == splits.Count)
				{
					Sb.Append("  ").Append(VarkourLocalization.FormatDelta(splits[i] - pbSplits[i]));
				}
				Sb.Append('\n');
			}
			RunHud.ShowResults(Sb.ToString());
		}

		private static void Cancel(string messageToken)
		{
			if (messageToken != null)
			{
				Notify.Center(VarkourLocalization.T(messageToken));
			}
			ClearRun();
			ModeMachine.ReturnToIdle();
			RunHud.SetMain(null);
		}

		private static void ClearRun()
		{
			ActiveCourse = null;
			NextZoneIndex = -1;
			Splits.Clear();
			_unrankedReason = null;
			_runCounter++;
		}

		private static string PbText(Course course)
		{
			if (!ClientCourses.TryGetPersonalBest(course, out var timeMs, out var _))
			{
				return VarkourLocalization.T("varkour_hud_no_pb");
			}
			return VarkourLocalization.T("varkour_hud_pb", VarkourLocalization.FormatTime(timeMs));
		}

		private static string RecordText(Course course)
		{
			string text = CourseRecordText(course);
			if (ClientCourses.IsDraft(course))
			{
				return text;
			}
			return text + "   " + VarkourLocalization.T("varkour_hud_runs", course.RunCount);
		}

		private static string CourseRecordText(Course course)
		{
			LeaderboardView leaderboard = ClientCourses.GetLeaderboard(course.Id);
			if (leaderboard == null || leaderboard.Top.Count <= 0)
			{
				return VarkourLocalization.T("varkour_hud_no_record");
			}
			return VarkourLocalization.T("varkour_hud_record", VarkourLocalization.FormatTime(leaderboard.Top[0].TimeMs), leaderboard.Top[0].PlayerName);
		}

		private static Course Refresh(Course course)
		{
			if (course == null)
			{
				return null;
			}
			return ClientCourses.GetPublished(course.Id) ?? ClientCourses.GetDraft(course.Id);
		}

		public static bool InZone(Zone zone, Vector3 pos)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (zone == null)
			{
				return false;
			}
			float num = pos.y - zone.Position.y;
			if (num > VarkourConfig.ZoneHeightAbove.Value || num < 0f - VarkourConfig.ZoneDepthBelow.Value)
			{
				return false;
			}
			float num2 = ((zone.Type == ZoneType.Checkpoint) ? (zone.Radius + 0.3f) : zone.Radius);
			return HorizontalDistance(zone.Position, pos) <= num2;
		}

		private static float HorizontalDistance(Vector3 a, Vector3 b)
		{
			//IL_0000: 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)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			float num = a.x - b.x;
			float num2 = a.z - b.z;
			return Mathf.Sqrt(num * num + num2 * num2);
		}

		private static float HorizontalSpeed(Player player)
		{
			//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)
			//IL_0007: 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)
			//IL_0014: 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)
			Vector3 velocity = ((Character)player).GetVelocity();
			return Mathf.Sqrt(velocity.x * velocity.x + velocity.z * velocity.z);
		}
	}
	internal static class RunHud
	{
		private static Text _main;

		private static Text _results;

		public static void SetMain(string text)
		{
			if (Ensure())
			{
				bool flag = !string.IsNullOrEmpty(text);
				if (flag && _main.text != text)
				{
					_main.text = text;
				}
				if (((Component)_main).gameObject.activeSelf != flag)
				{
					((Component)_main).gameObject.SetActive(flag);
				}
			}
		}

		public static void ShowResults(string text)
		{
			if (Ensure())
			{
				_results.text = text;
				((Component)_results).gameObject.SetActive(true);
			}
		}

		public static void HideResults()
		{
			if ((Object)(object)_results != (Object)null && ((Component)_results).gameObject.activeSelf)
			{
				((Component)_results).gameObject.SetActive(false);
			}
		}

		public static void Tick()
		{
			bool flag = (Object)(object)Hud.instance != (Object)null && Hud.instance.IsVisible();
			if ((Object)(object)_main != (Object)null && !flag && ((Component)_main).gameObject.activeSelf)
			{
				((Component)_main).gameObject.SetActive(false);
			}
			if (!flag)
			{
				HideResults();
			}
		}

		private static bool Ensure()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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_010b: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_main != (Object)null && (Object)(object)_results != (Object)null)
			{
				return true;
			}
			GameObject customGUIFront = GUIManager.CustomGUIFront;
			if ((Object)(object)customGUIFront == (Object)null)
			{
				return false;
			}
			GameObject obj = GUIManager.Instance.CreateText(string.Empty, customGUIFront.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -150f), GUIManager.Instance.AveriaSerifBold, 24, GUIManager.Instance.ValheimOrange, true, Color.black, 700f, 160f, false);
			((Object)obj).name = "Varkour_HudMain";
			_main = obj.GetComponent<Text>();
			_main.alignment = (TextAnchor)1;
			_main.supportRichText = true;
			((Graphic)_main).raycastTarget = false;
			obj.SetActive(false);
			GameObject obj2 = GUIManager.Instance.CreateText(string.Empty, customGUIFront.transform, new Vector2(1f, 0.5f), new Vector2(1f, 0.5f), new Vector2(-190f, 60f), GUIManager.Instance.AveriaSerifBold, 18, Color.white, true, Color.black, 340f, 520f, false);
			((Object)obj2).name = "Varkour_HudResults";
			_results = obj2.GetComponent<Text>();
			_results.alignment = (TextAnchor)3;
			_results.supportRichText = true;
			((Graphic)_results).raycastTarget = false;
			obj2.SetActive(false);
			return true;
		}
	}
	internal static class RunRules
	{
		public static string GetUnrankedReason(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			if (RunController.Practice)
			{
				return VarkourLocalization.T("varkour_unranked_practice");
			}
			if (player.InDebugFlyMode() || ((Character)player).IsDebugFlying())
			{
				return VarkourLocalization.T("varkour_unranked_fly");
			}
			if (((Character)player).InGodMode())
			{
				return VarkourLocalization.T("varkour_unranked_god");
			}
			if (player.NoCostCheat())
			{
				return VarkourLocalization.T("varkour_unranked_nocost");
			}
			return null;
		}
	}
}
namespace Varkour.Patches
{
	[HarmonyPatch]
	internal static class HardcoreParkourPatch
	{
		private static bool Applies(Character character)
		{
			return HardcoreParkour.IsActive(character);
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(Player), "GetJogSpeedFactor")]
		private static void CapJogFactor(Player __instance, ref float __result)
		{
			if (Applies((Character)(object)__instance) && __result > 1f)
			{
				__result = 1f;
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(Player), "GetRunSpeedFactor")]
		private static void CapRunFactor(Player __instance, ref float __result)
		{
			if (Applies((Character)(object)__instance) && __result > 1f)
			{
				__result = 1f;
			}
		}

		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(SEMan), "ApplyStatusEffectSpeedMods")]
		private static void RememberSpeed(ref float speed, out float __state)
		{
			__state = speed;
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(SEMan), "ApplyStatusEffectSpeedMods")]
		private static void CapStatusEffectSpeed(ref float speed, float __state, Character ___m_character)
		{
			if (Applies(___m_character))
			{
				speed = Mathf.Min(speed, __state);
			}
		}

		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(SEMan), "ApplyStatusEffectJumpMods")]
		private static void RememberJump(ref Vector3 jump, out Vector3 __state)
		{
			//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)
			__state = jump;
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(SEMan), "ApplyStatusEffectJumpMods")]
		private static void CapJump(ref Vector3 jump, Vector3 __state, Character ___m_character)
		{
			//IL_000f: 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_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_0052: 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)
			if (Applies(___m_character))
			{
				if (jump.y > __state.y)
				{
					jump.y = __state.y;
				}
				float num = jump.x * jump.x + jump.z * jump.z;
				float num2 = __state.x * __state.x + __state.z * __state.z;
				if (num > num2 && num > 0f)
				{
					float num3 = Mathf.Sqrt(num2 / num);
					jump.x *= num3;
					jump.z *= num3;
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(SEMan), "ModifyStaminaRegen")]
		private static void RememberRegen(ref float staminaMultiplier, out float __state)
		{
			__state = staminaMultiplier;
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(SEMan), "ModifyStaminaRegen")]
		private static void CapRegen(ref float staminaMultiplier, float __state, Character ___m_character)
		{
			if (Applies(___m_character))
			{
				staminaMultiplier = Mathf.Min(staminaMultiplier, __state);
			}
		}

		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(SEMan), "ModifyWalkVelocity")]
		private static void RememberVelocity(ref Vector3 vel, out Vector3 __state)
		{
			//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)
			__state = vel;
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(SEMan), "ModifyWalkVelocity")]
		private static void RestoreFallSpeed(ref Vector3 vel, Vector3 __state, Character ___m_character)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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)
			if (Applies(___m_character) && __state.y < 0f && vel.y > __state.y)
			{
				vel.y = __state.y;
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(SEMan), "ModifyFallDamage")]
		private static void NoFallDamage(ref float damage, Character ___m_character)
		{
			if (Applies(___m_character))
			{
				damage = 0f;
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
		private static void SetParkourStamina(Player __instance, ref float stamina)
		{
			if (HardcoreParkour.TryGetMaxStamina((Character)(object)__instance, out var maxStamina))
			{
				stamina = maxStamina;
			}
		}
	}
	[HarmonyPatch]
	internal static class PlacementPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		private static bool TryPlacePiece(Player __instance, Piece piece, ref bool __result)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (!MarkerPieces.TryGetZoneType(piece, out var type))
			{
				return true;
			}
			__result = false;
			if (!IsEditingLocalPlayer(__instance))
			{
				return false;
			}
			GameObject placementGhost = __instance.m_placementGhost;
			if ((Object)(object)placementGhost == (Object)null || !placementGhost.activeSelf)
			{
				((Character)__instance).Message((MessageType)2, VarkourLocalization.T("varkour_msg_no_surface"), 0, (Sprite)null, false);
				return false;
			}
			CourseEditor.PlaceZone(type, placementGhost.transform.position);
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "PlacePiece")]
		private static bool PlacePiece(Player __instance, Piece piece, Vector3 pos)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!MarkerPieces.TryGetZoneType(piece, out var type))
			{
				return true;
			}
			if (IsEditingLocalPlayer(__instance))
			{
				CourseEditor.PlaceZone(type, pos);
			}
			return false;
		}

		private static bool IsEditingLocalPlayer(Player player)
		{
			if (player == Player.m_localPlayer)
			{
				return ModeMachine.Current == VarkourMode.Editing;
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class WindowInputPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerController), "InInventoryEtc")]
		private static void StopMouseLook(ref bool __result)
		{
			if (VarkourWindow.CursorActive)
			{
				__result = true;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "TakeInput")]
		private static void NoWorldActions(ref bool __result)
		{
			if (VarkourWindow.CursorActive)
			{
				__result = false;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
		private static void FreeCursor()
		{
			if (VarkourWindow.CursorActive)
			{
				ZCursor.LockState = (CursorLockMode)0;
				ZCursor.Show();
			}
		}
	}
}
namespace Varkour.Net
{
	internal static class Packets
	{
		private const int MaxZonesOnWire = 1000;

		private const int MaxSplitsOnWire = 1000;

		private const int MaxCoursesOnWire = 100000;

		public static void WriteCourse(ZPackage pkg, Course c)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			pkg.Write(c.Id ?? string.Empty);
			pkg.Write(c.Name ?? string.Empty);
			pkg.Write(c.AuthorId);
			pkg.Write(c.AuthorName ?? string.Empty);
			pkg.Write(c.Version);
			pkg.Write(c.RunCount);
			pkg.Write(c.Zones.Count);
			foreach (Zone zone in c.Zones)
			{
				pkg.Write((int)zone.Type);
				pkg.Write(zone.Position);
				pkg.Write(zone.Radius);
			}
		}

		public static Course ReadCourse(ZPackage pkg)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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)
			Course course = new Course
			{
				Id = pkg.ReadString(),
				Name = pkg.ReadString(),
				AuthorId = pkg.ReadLong(),
				AuthorName = pkg.ReadString(),
				Version = pkg.ReadInt(),
				RunCount = pkg.ReadInt()
			};
			int num = Bounded(pkg.ReadInt(), 1000);
			course.Zones = new List<Zone>(num);
			for (int i = 0; i < num; i++)
			{
				int num2 = pkg.ReadInt();
				Vector3 position = pkg.ReadVector3();
				float radius = pkg.ReadSingle();
				course.Zones.Add(new Zone
				{
					Type = (ZoneType)Mathf.Clamp(num2, 0, 2),
					Position = position,
					Radius = radius
				});
			}
			return course;
		}

		public static void WriteCourses(ZPackage pkg, List<Course> courses)
		{
			pkg.Write(courses.Count);
			foreach (Course course in courses)
			{
				WriteCourse(pkg, course);
			}
		}

		public static List<Course> ReadCourses(ZPackage pkg)
		{
			int num = Bounded(pkg.ReadInt(), 100000);
			List<Course> list = new List<Course>(num);
			for (int i = 0; i < num; i++)
			{
				list.Add(ReadCourse(pkg));
			}
			return list;
		}

		public static void WriteSplits(ZPackage pkg, List<long> splits)
		{
			pkg.Write(splits.Count);
			foreach (long split in splits)
			{
				pkg.Write(split);
			}
		}

		public static List<long> ReadSplits(ZPackage pkg)
		{
			int num = Bounded(pkg.ReadInt(), 1000);
			List<long> list = new List<long>(num);
			for (int i = 0; i < num; i++)
			{
				list.Add(pkg.ReadLong());
			}
			return list;
		}

		public static void WriteRecord(ZPackage pkg, RunRecord r)
		{
			pkg.Write(r.CourseId ?? string.Empty);
			pkg.Write(r.CourseVersion);
			pkg.Write(r.PlayerId);
			pkg.Write(r.PlayerName ?? string.Empty);
			pkg.Write(r.TimeMs);
			pkg.Write(r.SetUtc ?? string.Empty);
			WriteSplits(pkg, r.SplitsMs ?? new List<long>());
		}

		public static RunRecord ReadRecord(ZPackage pkg)
		{
			return new RunRecord
			{
				CourseId = pkg.ReadString(),
				CourseVersion = pkg.ReadInt(),
				PlayerId = pkg.ReadLong(),
				PlayerName = pkg.ReadString(),
				TimeMs = pkg.ReadLong(),
				SetUtc = pkg.ReadString(),
				SplitsMs = ReadSplits(pkg)
			};
		}

		private static int Bounded(int value, int max)
		{
			if (value < 0 || value > max)
			{
				throw new InvalidDataException($"Count {value} out of range (max {max}).");
			}
			return value;
		}
	}
	internal struct CourseLimits
	{
		public int MaxNameLength;

		public int MaxZones;

		public float MinRadius;

		public float MaxRadius;
	}
	internal static class ServerRules
	{
		public const int MaxIdLength = 64;

		public static string ValidateCourse(Course c, CourseLimits limits)
		{
			if (c == null || string.IsNullOrEmpty(c.Id) || c.Id.Length > 64)
			{
				return "bad id";
			}
			string text = c.Name?.Trim();
			if (string.IsNullOrEmpty(text) || text.Length > limits.MaxNameLength || !CourseName.IsClean(text))
			{
				return "bad name";
			}
			if (c.Zones == null || c.Zones.Count < 2 || c.Zones.Count > limits.MaxZones)
			{
				return "zone count";
			}
			float num = Math.Min(limits.MinRadius, limits.MaxRadius) - 0.001f;
			float num2 = Math.Max(limits.MinRadius, limits.MaxRadius) + 0.001f;
			int num3 = 0;
			int num4 = 0;
			foreach (Zone zone in c.Zones)
			{
				if (zone.Type == ZoneType.Start)
				{
					num3++;
				}
				else if (zone.Type == ZoneType.End)
				{
					num4++;
				}
				if (!IsFinite(zone.Radius) || zone.Radius < num || zone.Radius > num2)
				{
					return "zone radius";
				}
				if (!IsFinite(zone.Position.x) || !IsFinite(zone.Position.y) || !IsFinite(zone.Position.z))
				{
					return "zone position";
				}
			}
			if (num3 != 1 || num4 != 1 || c.Zones[0].Type != ZoneType.Start || c.Zones[c.Zones.Count - 1].Type != ZoneType.End)
			{
				return "needs exactly one Start (first) and one End (last)";
			}
			return null;
		}

		public static string ValidateRun(Course course, long timeMs, List<long> splits)
		{
			if (timeMs <= 0)
			{
				return "time must be > 0";
			}
			if (splits == null || splits.Count != course.Zones.Count - 1)
			{
				return "split count mismatch";
			}
			long num = -1L;
			foreach (long split in splits)
			{
				if (split <= num)
				{
					return "splits must be strictly increasing";
				}
				num = split;
			}
			if (splits[splits.Count - 1] != timeMs)
			{
				return "last split must equal total time";
			}
			return null;
		}

		public static bool MayPublish(Course course, Course existing, long playerId, bool admin)
		{
			if (admin)
			{
				return true;
			}
			if (course.AuthorId == playerId)
			{
				if (existing != null)
				{
					return existing.AuthorId == playerId;
				}
				return true;
			}
			return false;
		}

		public static bool MayRemove(Course existing, long playerId, bool admin)
		{
			if (!admin)
			{
				return existing.AuthorId == playerId;
			}
			return true;
		}

		private static bool IsFinite(float f)
		{
			if (!float.IsNaN(f))
			{
				return !float.IsInfinity(f);
			}
			return false;
		}
	}
	internal static class ServerStore
	{
		public struct SubmitResult
		{
			public bool Accepted;

			public int Rank;

			public long RecordMs;
		}

		private const string FileName = "server.json";

		private static VarkourServerData _data;

		private static string _world;

		private static string _path;

		private static readonly List<RunRecord> Scratch = new List<RunRecord>();

		public static bool Loaded => _data != null;

		public static string WorldName => _world;

		public static List<Course> Courses => _data?.Courses ?? new List<Course>();

		public static CourseLimits Limits => new CourseLimits
		{
			MaxNameLength = VarkourConfig.MaxCourseNameLength.Value,
			MaxZones = VarkourConfig.MaxZonesPerCourse.Value,
			MinRadius = VarkourConfig.MinZoneRadius.Value,
			MaxRadius = VarkourConfig.MaxZoneRadius.Value
		};

		public static void Tick()
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null)
			{
				if (_data != null)
				{
					Unload();
				}
			}
			else if (instance.IsServer())
			{
				string worldName = instance.GetWorldName();
				if (!string.IsNullOrEmpty(worldName) && worldName != _world)
				{
					Load(worldName);
				}
			}
		}

		private static void Load(string world)
		{
			_world = world;
			_path = Path.Combine(JsonStore.WorldFolder(world), "server.json");
			_data = JsonStore.LoadServer(_path);
			if (_data == null)
			{
				VarkourPlugin.Log.LogError((object)("Server store for '" + world + "' is NOT loaded. Fix or remove " + _path + " and reload the world."));
				return;
			}
			_data.WorldName = world;
			_data.Courses = _data.Courses ?? new List<Course>();
			_data.Records = _data.Records ?? new List<RunRecord>();
			_data.Courses.RemoveAll((Course c) => c == null || string.IsNullOrEmpty(c.Id));
			VarkourPlugin.Log.LogInfo((object)$"Server store loaded for '{world}' from {_path}: {_data.Courses.Count} course(s), {_data.Records.Count} record(s).");
			VarkourNet.BroadcastFullSync();
		}

		public static void Unload()
		{
			if (_data != null)
			{
				Save();
			}
			_data = null;
			_world = null;
			_path = null;
		}

		private static void Save()
		{
			if (_data != null && _path != null)
			{
				JsonStore.Save(_path, _data);
			}
		}

		public static Course Get(string id)
		{
			if (_data == null || id == null)
			{
				return null;
			}
			foreach (Course course in _data.Courses)
			{
				if (course.Id == id)
				{
					return course;
				}
			}
			return null;
		}

		public static void Publish(Course course, RunRecord firstRun)
		{
			if (_data != null)
			{
				course.Name = course.Name.Trim();
				course.RunCount = 1;
				_data.Courses.RemoveAll((Course c) => c.Id == course.Id);
				_data.Courses.Add(course);
				_data.Records.RemoveAll((RunRecord r) => r.CourseId == course.Id);
				_data.Records.Add(firstRun);
				Save();
			}
		}

		public static Course Remove(string id)
		{
			Course course = Get(id);
			if (course == null)
			{
				return null;
			}
			_data.Courses.Remove(course);
			_data.Records.RemoveAll((RunRecord r) => r.CourseId == id);
			Save();
			return course;
		}

		public static void GetBoard(string courseId, List<RunRecord> into)
		{
			into.Clear();
			if (_data == null)
			{
				return;
			}
			foreach (RunRecord record in _data.Records)
			{
				if (record.CourseId == courseId)
				{
					into.Add(record);
				}
			}
			into.Sort(CompareRecords);
		}

		public static SubmitResult Submit(RunRecord record)
		{
			Course course = Get(record.CourseId);
			if (course != null)
			{
				course.RunCount++;
			}
			GetBoard(record.CourseId, Scratch);
			RunRecord runRecord = Scratch.Find((RunRecord r) => r.PlayerId == record.PlayerId);
			SubmitResult result = default(SubmitResult);
			if (runRecord != null && runRecord.TimeMs <= record.TimeMs)
			{
				result.Rank = Scratch.IndexOf(runRecord) + 1;
				result.RecordMs = Scratch[0].TimeMs;
				Save();
				return result;
			}
			if (runRecord != null)
			{
				_data.Records.Remove(runRecord);
				Scratch.Remove(runRecord);
			}
			_data.Records.Add(record);
			Scratch.Add(record);
			Scratch.Sort(CompareRecords);
			int value = VarkourConfig.LeaderboardSize.Value;
			for (int num = Scratch.Count - 1; num >= value; num--)
			{
				_data.Records.Remove(Scratch[num]);
				Scratch.RemoveAt(num);
			}
			result.Accepted = true;
			result.Rank = Scratch.IndexOf(record) + 1;
			result.RecordMs = Scratch[0].TimeMs;
			Save();
			return result;
		}

		public static string NowUtc()
		{
			return DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
		}

		private static int CompareRecords(RunRecord a, RunRecord b)
		{
			int num = a.TimeMs.CompareTo(b.TimeMs);
			if (num == 0)
			{
				return string.CompareOrdinal(a.SetUtc, b.SetUtc);
			}
			return num;
		}
	}
	internal static class VarkourNet
	{
		private enum RemoveReason : byte
		{
			Unpublish,
			Delete
		}

		private const byte SyncFull = 0;

		private const byte SyncUpsert = 1;

		private const byte SyncRemove = 2;

		private static CustomRPC _courseSyncRequest;

		private static CustomRPC _courseSync;

		private static CustomRPC _publish;

		private static CustomRPC _removeCourse;

		private static CustomRPC _submitRun;

		private static CustomRPC _requestLeaderboard;

		private static CustomRPC _leaderboardData;

		private static CustomRPC _newRecord;

		private static CustomRPC _serverNotice;

		private static readonly List<RunRecord> Board = new List<RunRecord>();

		private static long OwnId => ZDOMan.GetSessionID();

		private static long ServerId
		{
			get
			{
				ZNet instance = ZNet.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return 0L;
				}
				if (instance.IsServer())
				{
					return OwnId;
				}
				return instance.GetServerPeer()?.m_uid ?? 0;
			}
		}

		public static void Register()
		{
			//IL_001e: 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_0034: Expected O, but got Unknown
			//IL_0034: Expected O, but got Unknown
			//IL_004c: 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: Expected O, but got Unknown
			//IL_0062: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			//IL_0090: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_00be: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_00ec: Expected O, but got Unknown
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			//IL_011a: Expected O, but got Unknown
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_0148: Expected O, but got Unknown
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Expected O, but got Unknown
			//IL_0176: Expected O, but got Unknown
			//IL_018d: 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)
			//IL_01a3: Expected O, but got Unknown
			//IL_01a3: Expected O, but got Unknown
			NetworkManager instance = NetworkManager.Instance;
			string text = "Varkour_";
			_courseSyncRequest = instance.AddRPC(text + "CourseSyncRequest", new CoroutineHandler(OnCourseSyncRequest), new CoroutineHandler(Ignore));
			_courseSync = instance.AddRPC(text + "CourseSync", new CoroutineHandler(OnCourseSync), new CoroutineHandler(OnCourseSync));
			_publish = instance.AddRPC(text + "PublishCourse", new CoroutineHandler(OnPublish), new CoroutineHandler(Ignore));
			_removeCourse = instance.AddRPC(text + "RemoveCourse", new CoroutineHandler(OnRemoveCourse), new CoroutineHandler(Ignore));
			_submitRun = instance.AddRPC(text + "SubmitRun", new CoroutineHandler(OnSubmitRun), new CoroutineHandler(Ignore));
			_requestLeaderboard = instance.AddRPC(text + "RequestLeaderboard", new CoroutineHandler(OnRequestLeaderboard), new CoroutineHandler(Ignore));
			_leaderboardData = instance.AddRPC(text + "LeaderboardData", new CoroutineHandler(OnLeaderboardData), new CoroutineHandler(OnLeaderboardData));
			_newRecord = instance.AddRPC(text + "NewRecord", new CoroutineHandler(OnNewRecord), new CoroutineHandler(OnNewRecord));
			_serverNotice = instance.AddRPC(text + "ServerNotice", new CoroutineHandler(OnServerNotice), new CoroutineHandler(OnServerNotice));
		}

		private static bool SendToServer(CustomRPC rpc, ZPackage pkg, bool notifyIfOffline = true)
		{
			long serverId = ServerId;
			if (serverId == 0L || ZRoutedRpc.instance == null)
			{
				if (notifyIfOffline)
				{
					Notify.Center(VarkourLocalization.T("varkour_msg_server_offline"));
				}
				return false;
			}
			rpc.SendPackage(serverId, pkg);
			return true;
		}

		private static bool FromServer(long sender)
		{
			if (GUIManager.IsHeadless())
			{
				return false;
			}
			return sender == ServerId;
		}

		private static bool TryIdentify(long sender, out long playerId, out string playerName)
		{
			//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_007f: Unknown result type (might be due to invalid IL or missing references)
			playerId = 0L;
			playerName = null;
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			if (sender == OwnId && !instance.IsDedicated())
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null)
				{
					return false;
				}
				playerId = localPlayer.GetPlayerID();
				playerName = localPlayer.GetPlayerName();
				return playerId != 0;
			}
			ZNetPeer peer = instance.GetPeer(sender);
			if (peer == null || peer.m_characterID == ZDOID.None)
			{
				return false;
			}
			ZDO val = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(peer.m_characterID) : null);
			if (val == null)
			{
				return false;
			}
			playerId = val.GetLong(ZDOVars.s_playerID, 0L);
			playerName = (string.IsNullOrEmpty(peer.m_playerName) ? val.GetString(ZDOVars.s_playerName, "?") : peer.m_playerName);
			return playerId != 0;
		}

		private static bool Identify(long sender, long claimedId, string claimedName, out long playerId, out string playerName)
		{
			if (!TryIdentify(sender, out playerId, out playerName))
			{
				Notice(sender, "varkour_err_no_identity", string.Empty);
				return false;
			}
			if (claimedId != playerId || (claimedName != null && claimedName != playerName))
			{
				VarkourPlugin.Log.LogWarning((object)$"Peer {sender} ({playerName}, id {playerId}) sent a packet claiming to be {claimedName} (id {claimedId}); using the server's view.");
			}
			return true;
		}

		private static bool IsAdmin(long sender)
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			if (sender == OwnId && !instance.IsDedicated())
			{
				return true;
			}
			return ZNetExtension.IsAdmin(instance, sender);
		}

		private static void Broadcast(CustomRPC rpc, ZPackage pkg)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			ZNet instance = ZNet.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				byte[] array = pkg.GetArray();
				List<ZNetPeer> peers = instance.GetPeers();
				if (peers != null && peers.Count > 0)
				{
					rpc.SendPackage(new List<ZNetPeer>(peers), new ZPackage(array));
				}
				if (!instance.IsDedicated())
				{
					rpc.SendPackage(OwnId, new ZPackage(array));
				}
			}
		}

		private static IEnumerator Ignore(long sender, ZPackage pkg)
		{
			yield break;
		}

		public static bool RequestCourseSync()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			return SendToServer(_courseSyncRequest, new ZPackage(), notifyIfOffline: false);
		}

		public static void SendPublish(Course course, long timeMs, List<long> splits)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(ClientCourses.LocalPlayerId);
			val.Write(ClientCourses.LocalPlayerName);
			Packets.WriteCourse(val, course);
			val.Write(timeMs);
			Packets.WriteSplits(val, splits);
			VarkourPlugin.LogVerbose($"Sending PublishCourse '{course.Name}' to server {ServerId} (own {OwnId}).");
			SendToServer(_publish, val);
		}

		public static void SendUnpublish(string courseId)
		{
			SendRemove(courseId, RemoveReason.Unpublish);
		}

		public static void SendDelete(string courseId)
		{
			SendRemove(courseId, RemoveReason.Delete);
		}

		private static void SendRemove(string courseId, RemoveReason reason)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Un