Decompiled source of BalancedGliders v0.8.1

PIX_Balanced_Gliders.dll

Decompiled 15 hours ago
using System;
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 HarmonyLib;
using IBelieveICanFly.Patches;
using IBelieveICanFly.Registration;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
namespace Pix.BalancedGliders;

internal static class StableHashExtensions
{
	public static int GetStableHashCode(this string str)
	{
		if (str == null)
		{
			return 0;
		}
		int num = 5381;
		int num2 = num;
		for (int i = 0; i < str.Length && str[i] != 0; i += 2)
		{
			num = ((num << 5) + num) ^ str[i];
			if (i == str.Length - 1 || str[i + 1] == '\0')
			{
				break;
			}
			num2 = ((num2 << 5) + num2) ^ str[i + 1];
		}
		return num + num2 * 1566083941;
	}
}
[BepInPlugin("Pix.BalancedGliders", "Balanced Gliders", "0.8.1")]
public class Plugin : BaseUnityPlugin
{
	private static class Runtime
	{
		public static bool HasServerConfig;

		public static bool Enabled = true;

		public static float CooldownSeconds = 150f;

		public static bool DynamicEnabled = true;

		public static float DynamicBaseSeconds = 10f;

		public static float DynamicPower = 1.2f;

		public static float DynamicMultiplier = 2f;

		public static float DynamicMinSeconds = 10f;

		public static float DynamicMaxSeconds = 150f;

		public static float DynamicShortHopThresholdSeconds = 1f;

		public static bool ShowStatusEffect = true;

		public static bool DebugLogs;

		public static bool LeaderboardEnabled = true;

		public static KeyCode LeaderboardHotkey = (KeyCode)288;

		public static int LeaderboardMaxRows = 20;

		public static void LoadFromConfig()
		{
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			Enabled = _enabled != null && _enabled.Value;
			CooldownSeconds = ((_cooldownSeconds != null) ? _cooldownSeconds.Value : 150f);
			DynamicEnabled = _dynamicEnabled != null && _dynamicEnabled.Value;
			DynamicBaseSeconds = ((_dynamicBaseSeconds != null) ? _dynamicBaseSeconds.Value : 10f);
			DynamicPower = ((_dynamicPower != null) ? _dynamicPower.Value : 1.2f);
			DynamicMultiplier = ((_dynamicMultiplier != null) ? _dynamicMultiplier.Value : 2f);
			DynamicMinSeconds = ((_dynamicMinSeconds != null) ? _dynamicMinSeconds.Value : 10f);
			DynamicMaxSeconds = ((_dynamicMaxSeconds != null) ? _dynamicMaxSeconds.Value : 150f);
			DynamicShortHopThresholdSeconds = ((_dynamicShortHopThresholdSeconds != null) ? _dynamicShortHopThresholdSeconds.Value : 1f);
			ShowStatusEffect = _showStatusEffect != null && _showStatusEffect.Value;
			DebugLogs = _debugLogs != null && _debugLogs.Value;
			LeaderboardEnabled = _leaderboardEnabled != null && _leaderboardEnabled.Value;
			LeaderboardHotkey = (KeyCode)((_leaderboardHotkey == null) ? 288 : ((int)_leaderboardHotkey.Value));
			LeaderboardMaxRows = ((_leaderboardMaxRows != null) ? Mathf.Clamp(_leaderboardMaxRows.Value, 5, 100) : 20);
		}
	}

	private struct GlideTrack
	{
		public Vector3 StartPos;

		public long StartMs;
	}

	private sealed class RecordEntry
	{
		public long Id;

		public string Name;

		public float BestDistance;

		public float BestAirtime;

		public float BestDrop;

		public float LatestDistance;

		public float LatestAirtime;

		public float LatestDrop;

		public long UpdatedAtMs;
	}

	[HarmonyPatch(typeof(ZRoutedRpc))]
	private static class ZRoutedRpc_Ctor_Register_Patch
	{
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPostfix]
		private static void Postfix(bool server)
		{
			DetectRoutedRpcInstanceChange();
			TryRegisterRpcs();
		}
	}

	public class SE_GliderCooldown : SE_Stats
	{
		public override string GetIconText()
		{
			try
			{
				Character character = ((StatusEffect)this).m_character;
				Player val = (Player)(object)((character is Player) ? character : null);
				if ((Object)(object)val == (Object)null)
				{
					return "";
				}
				if (!IsOnCooldown(val, out var remainingSeconds))
				{
					return "";
				}
				return FormatSeconds(remainingSeconds);
			}
			catch
			{
				return "";
			}
		}
	}

	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	private static class ObjectDB_RegisterStatusEffect_Patch
	{
		private static void Postfix(ObjectDB __instance)
		{
			EnsureSEInObjectDB(__instance);
		}
	}

	[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
	private static class ObjectDB_CopyOtherDB_RegisterStatusEffect_Patch
	{
		private static void Postfix(ObjectDB __instance)
		{
			EnsureSEInObjectDB(__instance);
		}
	}

	[HarmonyPatch]
	private static class GliderSystemPatches
	{
		[HarmonyPatch(typeof(GliderSystem), "CanGlide")]
		[HarmonyPostfix]
		private static void CanGlide_Postfix(Player player, ref bool __result)
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!EffectiveEnabled || (Object)(object)player == (Object)null)
				{
					return;
				}
				bool flag = __result;
				bool flag2 = WasGliding(player);
				if (flag2)
				{
					return;
				}
				float remainingSeconds = 0f;
				bool flag3 = IsOnCooldown(player, out remainingSeconds);
				bool flag4 = false;
				bool flag5 = false;
				int num = -1;
				float num2 = 0f;
				bool flag6 = false;
				bool flag7 = false;
				bool flag8 = false;
				bool flag9 = false;
				bool flag10 = false;
				float num3 = 0f;
				try
				{
					flag8 = ((Character)player).IsOnGround();
				}
				catch
				{
				}
				try
				{
					flag9 = ((Character)player).InWater();
				}
				catch
				{
				}
				try
				{
					flag10 = ((Character)player).IsAttached();
				}
				catch
				{
				}
				try
				{
					Rigidbody component = ((Component)player).GetComponent<Rigidbody>();
					if ((Object)component != (Object)null)
					{
						num3 = component.linearVelocity.y;
					}
				}
				catch
				{
				}
				try
				{
					flag6 = Input.GetKey((KeyCode)32);
					flag7 = Input.GetKeyDown((KeyCode)32);
				}
				catch
				{
				}
				try
				{
					if (Config.ToggleMode != null)
					{
						flag4 = Config.ToggleMode.Value;
					}
				}
				catch
				{
				}
				try
				{
					flag5 = _frToggleModeActive.Invoke((object)null);
				}
				catch
				{
				}
				try
				{
					num = _frCurrentWingsIndex.Invoke((object)null);
				}
				catch
				{
				}
				try
				{
					int num4 = num;
					if (num4 <= 0)
					{
						num4 = GliderSystem.GetCurrentWingsIndex();
					}
					if (num4 > 0)
					{
						num2 = Config.GetWingsMinActivationFallSpeed(num4);
					}
				}
				catch
				{
				}
				if (EffectiveDebug && (flag6 || flag7) && Time.unscaledTime >= _dbgNextCanGlideAt)
				{
					_dbgNextCanGlideAt = Time.unscaledTime + 0.5f;
					bool flag11 = (Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer;
					Dbg("CanGlide hb: " + $"upstream={flag} " + string.Format("cd={0} rem={1:0.00}s veto={2} ", flag3 ? "YES" : "NO", remainingSeconds, flag && flag3) + $"wasGliding={flag2} local={flag11} " + $"grounded={flag8} water={flag9} attached={flag10} " + $"vy={num3:0.00} minFall={num2:0.00} " + $"spaceHeld={flag6} spaceDown={flag7} " + $"toggleCfg={flag4} toggleActive={flag5} wingsIdx={num}");
				}
				if (flag && flag3)
				{
					__result = false;
				}
			}
			catch
			{
			}
		}

		[HarmonyPatch(typeof(GliderSystem), "StartGliding")]
		[HarmonyPostfix]
		private static void StartGliding_Postfix(Player player)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			try
			{
				if (EffectiveEnabled && !((Object)(object)player == (Object)null))
				{
					MarkGliding(player, gliding: true);
					if (!IsServer() && (Object)(object)player == (Object)(object)Player.m_localPlayer && IsNetConnected() && ZRoutedRpc.instance != null)
					{
						ZPackage val = new ZPackage();
						val.Write(GetNetworkTimeMs());
						ZRoutedRpc.instance.InvokeRoutedRPC("BG_GlideStart", new object[1] { val });
					}
				}
			}
			catch
			{
			}
		}

		[HarmonyPatch(typeof(GliderSystem), "StopGliding")]
		[HarmonyPostfix]
		private static void StopGliding_Postfix(Player player)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			try
			{
				if (EffectiveEnabled && !((Object)(object)player == (Object)null))
				{
					MarkGliding(player, gliding: false);
					if (!IsServer() && (Object)(object)player == (Object)(object)Player.m_localPlayer && IsNetConnected() && ZRoutedRpc.instance != null)
					{
						ZPackage val = new ZPackage();
						val.Write(GetNetworkTimeMs());
						ZRoutedRpc.instance.InvokeRoutedRPC("BG_GlideEnd", new object[1] { val });
					}
				}
			}
			catch
			{
			}
		}

		[HarmonyPatch(typeof(GliderSystem), "IsPlayerGliding")]
		[HarmonyPostfix]
		private static void IsPlayerGliding_Postfix(Player player, ref bool __result)
		{
			try
			{
				if (!((Object)(object)player == (Object)null))
				{
					MarkGliding(player, __result);
				}
			}
			catch
			{
			}
		}
	}

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

		public static Action <>9__95_0;

		public static ConsoleEvent <>9__115_0;

		public static ConsoleEvent <>9__115_1;

		public static Comparison<RecordEntry> <>9__127_0;

		internal void <HookServerConfigEvents>b__95_0()
		{
			Runtime.LoadFromConfig();
			BroadcastServerConfig();
		}

		internal void <TryRegisterCommands>b__115_0(ConsoleEventArgs args)
		{
			OutputClient(BuildStatusText(), hud: false);
		}

		internal void <TryRegisterCommands>b__115_1(ConsoleEventArgs args)
		{
			if (!EffectiveLeaderboard)
			{
				OutputClient("Balanced Gliders: leaderboard is disabled.", hud: true);
				return;
			}
			_lbVisible = !_lbVisible;
			if (_lbVisible)
			{
				if (string.IsNullOrEmpty(_lbText))
				{
					_lbText = "Loading leaderboard...";
				}
				RequestLeaderboardIfClient();
			}
		}

		internal int <BuildLeaderboardText_Server>b__127_0(RecordEntry a, RecordEntry b)
		{
			return b.BestDistance.CompareTo(a.BestDistance);
		}
	}

	public const string PluginGuid = "Pix.BalancedGliders";

	public const string PluginName = "Balanced Gliders";

	public const string PluginVersion = "0.8.1";

	private Harmony _harmony;

	private static ConfigEntry<bool> _enabled;

	private static ConfigEntry<float> _cooldownSeconds;

	private static ConfigEntry<bool> _dynamicEnabled;

	private static ConfigEntry<float> _dynamicBaseSeconds;

	private static ConfigEntry<float> _dynamicPower;

	private static ConfigEntry<float> _dynamicMultiplier;

	private static ConfigEntry<float> _dynamicMinSeconds;

	private static ConfigEntry<float> _dynamicMaxSeconds;

	private static ConfigEntry<float> _dynamicShortHopThresholdSeconds;

	private static ConfigEntry<bool> _showStatusEffect;

	private static ConfigEntry<bool> _debugLogs;

	private static ConfigEntry<bool> _serverAuthoritativeConfig;

	private static ConfigEntry<bool> _lockClientConfig;

	private static ConfigEntry<bool> _leaderboardEnabled;

	private static ConfigEntry<KeyCode> _leaderboardHotkey;

	private static ConfigEntry<int> _leaderboardMaxRows;

	private static ConfigEntry<string> _toastVariantsAllTimePB;

	private static ConfigEntry<string> _toastVariantsDailyPB;

	private static ConfigEntry<string> _toastVariantsNormal;

	private static readonly int ZdoKey_CooldownEndMs = "BG_CooldownEndMs".GetStableHashCode();

	private static readonly int ZdoKey_GlideStartMs = "BG_GlideStartMs".GetStableHashCode();

	private const string Rpc_RequestConfig = "BG_RequestConfig";

	private const string Rpc_ReceiveConfig = "BG_Config";

	private const string Rpc_GlideStart = "BG_GlideStart";

	private const string Rpc_GlideEnd = "BG_GlideEnd";

	private const string Rpc_SetCooldown = "BG_SetCooldown";

	private const string Rpc_RequestLeaderboard = "BG_LB_Req";

	private const string Rpc_ReceiveLeaderboard = "BG_LB_Recv";

	private const string Rpc_GlideResult = "BG_GlideResult";

	private const string CooldownSEName = "SE_BalancedGliders_Cooldown";

	private static readonly int CooldownSEHash = "SE_BalancedGliders_Cooldown".GetStableHashCode();

	private static StatusEffect _cooldownSEPrefab;

	private static readonly FieldRef<Character, ZNetView> _frNView = AccessTools.FieldRefAccess<Character, ZNetView>("m_nview");

	private static readonly FieldRef<object, bool> _frToggleModeActive = AccessTools.FieldRefAccess<bool>(typeof(GliderSystem), "toggleModeActive");

	private static readonly FieldRef<object, int> _frCurrentWingsIndex = AccessTools.FieldRefAccess<int>(typeof(GliderSystem), "currentWingsIndex");

	private static readonly Dictionary<ZDOID, bool> _wasGlidingByZdo = new Dictionary<ZDOID, bool>();

	private static readonly Dictionary<long, bool> _wasGlidingByPlayerId = new Dictionary<long, bool>();

	private static readonly Dictionary<ZDOID, GlideTrack> _glideTrackByZdo = new Dictionary<ZDOID, GlideTrack>();

	private static readonly Dictionary<long, RecordEntry> _recordsById = new Dictionary<long, RecordEntry>();

	private static readonly Dictionary<long, float> _dailyBestById = new Dictionary<long, float>();

	private static bool _recordsDirty;

	private static float _nextRecordsSaveAt;

	private static string _recordsPath;

	private float _localCleanupTimer;

	private float _patchCheckTimer;

	private static bool _rpcsRegistered;

	private static bool _serverConfigHooksInstalled;

	private static bool _serverBroadcastedInitialConfig;

	private static bool _requestedServerConfig;

	private static float _requestTimer;

	private static bool _wasConnectedLastTick;

	private static ZRoutedRpc _lastRoutedRpcInstance;

	private static bool _commandsRegistered;

	private static bool _lbVisible;

	private static float _lbLastRequestAt;

	private static string _lbText = "";

	private static string _toastText;

	private static float _toastUntil;

	private static bool _guiInit;

	private static GUIStyle _lbTitleStyle;

	private static GUIStyle _lbBodyStyle;

	private static GUIStyle _lbFooterStyle;

	private static GUIStyle _lbPanelStyle;

	private static bool _trophyIconTried;

	private static Sprite _trophyIconSprite;

	private static bool _panelBackingTried;

	private static bool _panelBackingHas;

	private static Texture2D _panelBackingTex;

	private static Rect _panelBackingUv;

	private static float _dbgNextCanGlideAt;

	private static bool EffectiveEnabled => ShouldUseServerRuntime() ? Runtime.Enabled : (_enabled != null && _enabled.Value);

	private static bool EffectiveShowSE => ShouldUseServerRuntime() ? Runtime.ShowStatusEffect : (_showStatusEffect != null && _showStatusEffect.Value);

	private static bool EffectiveDebug => ShouldUseServerRuntime() ? Runtime.DebugLogs : (_debugLogs != null && _debugLogs.Value);

	private static bool EffectiveLeaderboard => ShouldUseServerRuntime() ? Runtime.LeaderboardEnabled : (_leaderboardEnabled != null && _leaderboardEnabled.Value);

	private static KeyCode EffectiveLeaderboardHotkey => (KeyCode)((!ShouldUseServerRuntime()) ? ((_leaderboardHotkey == null) ? 288 : ((int)_leaderboardHotkey.Value)) : ((int)Runtime.LeaderboardHotkey));

	private static int EffectiveLeaderboardMaxRows => ShouldUseServerRuntime() ? Runtime.LeaderboardMaxRows : ((_leaderboardMaxRows != null) ? Mathf.Clamp(_leaderboardMaxRows.Value, 5, 100) : 20);

	private void Awake()
	{
		//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02be: Expected O, but got Unknown
		_serverAuthoritativeConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "ServerAuthoritativeConfig", true, "If true, the server's config values override clients (no ServerSync dependency).");
		_lockClientConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "LockClientConfig", true, "If true and ServerAuthoritativeConfig is enabled, clients always obey server values when connected.");
		_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable cooldown enforcement.");
		_cooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Cooldown", "CooldownSeconds", 150f, "Fixed cooldown seconds after gliding (used when DynamicCooldown is disabled).");
		_dynamicEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("DynamicCooldown", "Enabled", true, "Enable dynamic cooldown based on seconds spent gliding (server-enforced).");
		_dynamicBaseSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("DynamicCooldown", "BaseSeconds", 10f, "Base cooldown seconds added for a glide longer than the short-hop threshold.");
		_dynamicPower = ((BaseUnityPlugin)this).Config.Bind<float>("DynamicCooldown", "Power", 1.2f, "Exponent applied to glide duration. Higher = ramps faster for long glides.");
		_dynamicMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("DynamicCooldown", "Multiplier", 2f, "Multiplier applied after exponent. Higher = more cooldown per glide second.");
		_dynamicMinSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("DynamicCooldown", "MinSeconds", 10f, "Minimum cooldown seconds (also used for short hops).");
		_dynamicMaxSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("DynamicCooldown", "MaxSeconds", 150f, "Maximum cooldown seconds cap.");
		_dynamicShortHopThresholdSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("DynamicCooldown", "ShortHopThresholdSeconds", 1f, "Glides with duration <= this threshold use MinSeconds cooldown.");
		_showStatusEffect = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowStatusEffect", true, "Show a cooldown status effect with a countdown timer.");
		_leaderboardEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Leaderboard", "Enabled", true, "Enable server-persistent leaderboard + hotkey.");
		_leaderboardHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Leaderboard", "Hotkey", (KeyCode)288, "Hotkey to toggle leaderboard display (client-side).");
		_leaderboardMaxRows = ((BaseUnityPlugin)this).Config.Bind<int>("Leaderboard", "MaxRows", 20, "Rows to show in the leaderboard display.");
		_toastVariantsAllTimePB = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "ToastVariantsAllTimePB", "ALL-TIME PB! {dist}m|New ALL-TIME record: {dist}m|Skål! All-time PB: {dist}m|Legendary! ALL-TIME {dist}m", "Client-only: '|' separated toasts for ALL-TIME PB. Placeholders: {dist}, {dist1}, {name}, {when}");
		_toastVariantsDailyPB = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "ToastVariantsDailyPB", "Daily PB! {dist}m|New session best: {dist}m|Nice — daily best {dist}m|Fresh start, new PB {dist}m", "Client-only: '|' separated toasts for DAILY (per-login) PB. Placeholders: {dist}, {dist1}, {name}, {when}");
		_toastVariantsNormal = ((BaseUnityPlugin)this).Config.Bind<string>("UI", "ToastVariantsGlideComplete", "You traveled {dist}m|Glide complete: {dist}m|Nice run — {dist}m|Distance: {dist}m", "Client-only: '|' separated toasts for normal results. Placeholders: {dist}, {dist1}, {name}, {when}");
		_debugLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogs", false, "Verbose debug logging.");
		Runtime.LoadFromConfig();
		_recordsPath = Path.Combine(Paths.ConfigPath, "BalancedGliders_Leaderboard.txt");
		LoadRecordsFromDisk();
		_harmony = new Harmony("Pix.BalancedGliders");
		ApplyAllHarmonyPatches();
	}

	private void ApplyAllHarmonyPatches()
	{
		try
		{
			_harmony.PatchAll(typeof(ObjectDB_RegisterStatusEffect_Patch));
			_harmony.PatchAll(typeof(ObjectDB_CopyOtherDB_RegisterStatusEffect_Patch));
			_harmony.PatchAll(typeof(GliderSystemPatches));
			_harmony.PatchAll(typeof(ZRoutedRpc_Ctor_Register_Patch));
		}
		catch (Exception arg)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)string.Format("[{0}] PatchAll failed: {1}", "Balanced Gliders", arg));
		}
	}

	private void Update()
	{
		//IL_0264: Unknown result type (might be due to invalid IL or missing references)
		bool flag = IsNetConnected();
		if (flag != _wasConnectedLastTick)
		{
			_wasConnectedLastTick = flag;
			_requestedServerConfig = false;
			Runtime.HasServerConfig = false;
			_requestTimer = 0f;
			_wasGlidingByZdo.Clear();
			_wasGlidingByPlayerId.Clear();
			_dailyBestById.Clear();
			if (IsServer())
			{
				_glideTrackByZdo.Clear();
			}
			if (!flag)
			{
				_lbVisible = false;
				_lbText = "";
			}
			_panelBackingTried = false;
			_panelBackingHas = false;
			_panelBackingTex = null;
			_trophyIconTried = false;
			_trophyIconSprite = null;
			EnsureHarmonyStillPatched(forceLog: true);
		}
		_patchCheckTimer += Time.unscaledDeltaTime;
		if (_patchCheckTimer >= 5f)
		{
			_patchCheckTimer = 0f;
			EnsureHarmonyStillPatched(forceLog: false);
		}
		DetectRoutedRpcInstanceChange();
		TryRegisterRpcs();
		TryRegisterCommands();
		if (IsServer() && !_serverConfigHooksInstalled)
		{
			HookServerConfigEvents();
			_serverConfigHooksInstalled = true;
		}
		if (IsServer() && _rpcsRegistered && !_serverBroadcastedInitialConfig)
		{
			Runtime.LoadFromConfig();
			BroadcastServerConfig();
			_serverBroadcastedInitialConfig = true;
		}
		if (!IsServer() && _serverAuthoritativeConfig != null && _serverAuthoritativeConfig.Value && !_requestedServerConfig && flag)
		{
			_requestTimer += Time.unscaledDeltaTime;
			if (_requestTimer >= 1.5f)
			{
				_requestTimer = 0f;
				RequestServerConfig();
				_requestedServerConfig = true;
			}
		}
		if (IsServer() && _recordsDirty && Time.unscaledTime >= _nextRecordsSaveAt)
		{
			SaveRecordsToDisk();
		}
		if (_toastUntil > 0f && Time.unscaledTime <= _toastUntil && !string.IsNullOrEmpty(_toastText))
		{
			ShowHud((MessageType)2, _toastText);
			_toastUntil = 0f;
			_toastText = null;
		}
		if (EffectiveLeaderboard && flag && !IsTypingOrConsoleOpen() && ZInput.GetKeyDown(EffectiveLeaderboardHotkey, true))
		{
			_lbVisible = !_lbVisible;
			if (_lbVisible)
			{
				if (string.IsNullOrEmpty(_lbText))
				{
					_lbText = "Loading leaderboard...";
				}
				RequestLeaderboardIfClient();
			}
		}
		if (_lbVisible && (!flag || !EffectiveLeaderboard))
		{
			_lbVisible = false;
		}
		_localCleanupTimer += Time.unscaledDeltaTime;
		if (_localCleanupTimer < 0.25f)
		{
			return;
		}
		_localCleanupTimer = 0f;
		try
		{
			if (!EffectiveShowSE)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && ((Character)localPlayer).IsOwner())
			{
				if (!IsOnCooldown(localPlayer, out var _))
				{
					RemoveCooldownStatusEffectIfPresent(localPlayer);
				}
				else
				{
					EnsureCooldownStatusEffect(localPlayer);
				}
			}
		}
		catch
		{
		}
	}

	private void OnGUI()
	{
		//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_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0504: Unknown result type (might be due to invalid IL or missing references)
		//IL_050b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Expected O, but got Unknown
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Expected O, but got Unknown
		//IL_0145: 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_01ee: Expected O, but got Unknown
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0203: Expected O, but got Unknown
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Expected O, but got Unknown
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0233: Unknown result type (might be due to invalid IL or missing references)
		//IL_023f: Expected O, but got Unknown
		//IL_0334: 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_030e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0319: Unknown result type (might be due to invalid IL or missing references)
		//IL_0320: Unknown result type (might be due to invalid IL or missing references)
		//IL_032c: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_041e: Unknown result type (might be due to invalid IL or missing references)
		//IL_042a: Expected O, but got Unknown
		//IL_0489: Unknown result type (might be due to invalid IL or missing references)
		//IL_0450: Unknown result type (might be due to invalid IL or missing references)
		//IL_046b: Unknown result type (might be due to invalid IL or missing references)
		Matrix4x4 matrix = GUI.matrix;
		Color color = GUI.color;
		try
		{
			GUI.matrix = Matrix4x4.identity;
			if (!_lbVisible || !IsNetConnected() || !EffectiveLeaderboard || IsTypingOrConsoleOpen())
			{
				return;
			}
			EnsureLeaderboardGuiStyles();
			EnsureValheimPanelBacking();
			EnsureFirstPlaceTrophyIcon();
			_lbTitleStyle.wordWrap = true;
			_lbBodyStyle.wordWrap = true;
			_lbFooterStyle.wordWrap = true;
			string text = "BALANCED GLIDERS — TOP GLIDES";
			string text2 = (string.IsNullOrEmpty(_lbText) ? "Loading leaderboard..." : _lbText);
			string[] array = text2.Replace("\r", "").Split(new char[1] { '\n' });
			string text3 = $"{EffectiveLeaderboardHotkey} = Toggle Leaderboard";
			float num = 16f;
			float num2 = 6f;
			float num3 = (float)Screen.width - 40f;
			float num4 = 380f;
			float num5 = 0f;
			num5 = Mathf.Max(num5, _lbTitleStyle.CalcSize(new GUIContent(text)).x);
			num5 = Mathf.Max(num5, _lbFooterStyle.CalcSize(new GUIContent(text3)).x);
			for (int i = 0; i < array.Length; i++)
			{
				string text4 = (string.IsNullOrEmpty(array[i]) ? " " : array[i]);
				float x = _lbBodyStyle.CalcSize(new GUIContent(text4)).x;
				if (x > num5)
				{
					num5 = x;
				}
			}
			float num6 = Mathf.Clamp(num5 + num * 2f + 10f, num4, num3);
			float num7 = num6 - num * 2f;
			float num8 = _lbTitleStyle.CalcHeight(new GUIContent(text), num7);
			float num9 = _lbFooterStyle.CalcHeight(new GUIContent(text3), num7);
			float num10 = 0f;
			for (int j = 0; j < array.Length; j++)
			{
				string text5 = (string.IsNullOrEmpty(array[j]) ? " " : array[j]);
				float num11 = _lbBodyStyle.CalcHeight(new GUIContent(text5), num7);
				num10 += num11;
				if (j != array.Length - 1)
				{
					num10 += num2;
				}
			}
			float num12 = num + num8 + 12f + num10 + 12f + num9 + num + 10f;
			float num13 = ((float)Screen.width - num6) * 0.5f;
			float num14 = Mathf.Clamp((float)Screen.height * 0.18f, 70f, (float)Screen.height - num12 - 40f);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(num13, num14, num6, num12);
			if (_panelBackingHas && (Object)(object)_panelBackingTex != (Object)null)
			{
				float panelDarkenMultiplier = GetPanelDarkenMultiplier();
				GUI.color = new Color(panelDarkenMultiplier, panelDarkenMultiplier, panelDarkenMultiplier, 1f);
				GUI.DrawTextureWithTexCoords(val, (Texture)(object)_panelBackingTex, _panelBackingUv, true);
				GUI.color = color;
			}
			GUI.Box(val, GUIContent.none, _lbPanelStyle);
			float num15 = ((Rect)(ref val)).x + num;
			float num16 = ((Rect)(ref val)).y + num;
			GUI.Label(new Rect(num15, num16, num7, num8), text, _lbTitleStyle);
			num16 += num8 + 12f;
			float num17 = 18f;
			float num18 = 6f;
			for (int k = 0; k < array.Length; k++)
			{
				string text6 = (string.IsNullOrEmpty(array[k]) ? " " : array[k]);
				bool flag = k == 0;
				Sprite val2 = null;
				if (flag)
				{
					val2 = _trophyIconSprite;
					if ((Object)(object)val2 == (Object)null)
					{
						val2 = GetFirstPlaceFallbackSprite();
					}
				}
				float num19 = ((flag && (Object)(object)val2 != (Object)null) ? (num7 - (num17 + num18)) : num7);
				if (num19 < 60f)
				{
					num19 = 60f;
				}
				float num20 = _lbBodyStyle.CalcHeight(new GUIContent(text6), num19);
				if (flag && (Object)(object)val2 != (Object)null)
				{
					DrawSprite(new Rect(num15, num16 + 2f, num17, num17), val2);
					GUI.Label(new Rect(num15 + num17 + num18, num16, num19, num20), text6, _lbBodyStyle);
				}
				else
				{
					GUI.Label(new Rect(num15, num16, num7, num20), text6, _lbBodyStyle);
				}
				num16 += num20;
				if (k != array.Length - 1)
				{
					num16 += num2;
				}
			}
			num16 += 12f;
			GUI.Label(new Rect(num15, num16, num7, num9), text3, _lbFooterStyle);
		}
		catch
		{
		}
		finally
		{
			GUI.color = color;
			GUI.matrix = matrix;
		}
	}

	private static void Dbg(string msg)
	{
		try
		{
			if (EffectiveDebug && !string.IsNullOrEmpty(msg))
			{
				Debug.Log((object)("[BalancedGliders] " + msg));
			}
		}
		catch
		{
		}
	}

	private static void EnsureFirstPlaceTrophyIcon()
	{
		if (_trophyIconTried)
		{
			return;
		}
		_trophyIconTried = true;
		try
		{
			if ((Object)(object)InventoryGui.instance == (Object)null)
			{
				return;
			}
			Image[] componentsInChildren = ((Component)InventoryGui.instance).GetComponentsInChildren<Image>(true);
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				return;
			}
			foreach (Image val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.sprite == (Object)null))
				{
					string text = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : "");
					string text2 = ((Object)val.sprite).name ?? "";
					string text3 = text.ToLowerInvariant();
					string text4 = text2.ToLowerInvariant();
					if (text3.Contains("troph") || text4.Contains("troph"))
					{
						_trophyIconSprite = val.sprite;
						break;
					}
				}
			}
		}
		catch
		{
			_trophyIconSprite = null;
		}
	}

	private static void DrawSprite(Rect rect, Sprite sprite)
	{
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: 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)
		if (!((Object)(object)sprite == (Object)null))
		{
			Texture2D texture = sprite.texture;
			if (!((Object)(object)texture == (Object)null))
			{
				Rect textureRect = sprite.textureRect;
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(((Rect)(ref textureRect)).x / (float)((Texture)texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)texture).height, ((Rect)(ref textureRect)).width / (float)((Texture)texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)texture).height);
				GUI.DrawTextureWithTexCoords(rect, (Texture)(object)texture, val, true);
			}
		}
	}

	private static float GetPanelDarkenMultiplier()
	{
		return IsNightTime() ? 0.8f : 1f;
	}

	private static bool IsNightTime()
	{
		try
		{
			try
			{
				bool flag = EnvMan.IsDay();
				return !flag;
			}
			catch
			{
			}
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			try
			{
				float dayFraction = instance.GetDayFraction();
				return dayFraction < 0.25f || dayFraction > 0.75f;
			}
			catch
			{
			}
		}
		catch
		{
		}
		return false;
	}

	private static void EnsureLeaderboardGuiStyles()
	{
		//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_0026: 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_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Expected O, but got Unknown
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: 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_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Expected O, but got Unknown
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Expected O, but got Unknown
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Expected O, but got Unknown
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Expected O, but got Unknown
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		if (!_guiInit)
		{
			_lbTitleStyle = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)1,
				fontStyle = (FontStyle)1,
				fontSize = 22,
				wordWrap = true
			};
			_lbBodyStyle = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)0,
				fontStyle = (FontStyle)0,
				fontSize = 18,
				wordWrap = true
			};
			_lbFooterStyle = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)1,
				fontStyle = (FontStyle)1,
				fontSize = 14,
				wordWrap = true
			};
			_lbPanelStyle = new GUIStyle(GUI.skin.box);
			_lbPanelStyle.padding = new RectOffset(16, 16, 16, 16);
			_lbTitleStyle.normal.textColor = new Color(0.93f, 0.78f, 0.46f, 1f);
			_lbFooterStyle.normal.textColor = new Color(0.9f, 0.83f, 0.65f, 1f);
			_lbBodyStyle.normal.textColor = new Color(0.95f, 0.95f, 0.95f, 1f);
			_guiInit = true;
		}
	}

	private static void EnsureValheimPanelBacking()
	{
		//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_033e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0340: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		if (_panelBackingTried)
		{
			return;
		}
		_panelBackingTried = true;
		try
		{
			if ((Object)(object)InventoryGui.instance == (Object)null)
			{
				return;
			}
			Image[] componentsInChildren = ((Component)InventoryGui.instance).GetComponentsInChildren<Image>(true);
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				return;
			}
			Image val = null;
			float num = -1f;
			foreach (Image val2 in componentsInChildren)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				Sprite sprite = val2.sprite;
				if ((Object)(object)sprite == (Object)null || (Object)(object)sprite.texture == (Object)null)
				{
					continue;
				}
				Rect val3 = (Rect)(((Object)(object)((Graphic)val2).rectTransform != (Object)null) ? ((Graphic)val2).rectTransform.rect : default(Rect));
				float num2 = Mathf.Abs(((Rect)(ref val3)).width * ((Rect)(ref val3)).height);
				if (num2 < 20000f)
				{
					continue;
				}
				string text = (((Object)sprite).name ?? "").ToLowerInvariant();
				if (!text.Contains("tooltip") && !text.Contains("tip") && !text.Contains("scroll") && !text.Contains("button") && !text.Contains("icon") && !text.Contains("small") && !text.Contains("border") && !text.Contains("frame_small") && !text.Contains("paper") && !text.Contains("parch") && !text.Contains("list"))
				{
					float num3 = num2;
					bool flag = text.Contains("wood");
					bool flag2 = text.Contains("panel") || text.Contains("back") || text.Contains("bg");
					if (flag)
					{
						num3 *= 1.5f;
					}
					else if (flag2)
					{
						num3 *= 1.2f;
					}
					float num4 = ((Mathf.Abs(((Rect)(ref val3)).height) > 0.01f) ? Mathf.Abs(((Rect)(ref val3)).width / ((Rect)(ref val3)).height) : 1f);
					if (num4 >= 1.5f && num4 <= 4f)
					{
						num3 *= 1.1f;
					}
					if (num3 > num)
					{
						num = num3;
						val = val2;
					}
				}
			}
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val.sprite == (Object)null) && !((Object)(object)val.sprite.texture == (Object)null))
			{
				Texture2D texture = val.sprite.texture;
				Rect textureRect = val.sprite.textureRect;
				Rect panelBackingUv = default(Rect);
				((Rect)(ref panelBackingUv))..ctor(((Rect)(ref textureRect)).x / (float)((Texture)texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)texture).height, ((Rect)(ref textureRect)).width / (float)((Texture)texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)texture).height);
				_panelBackingTex = texture;
				_panelBackingUv = panelBackingUv;
				_panelBackingHas = true;
			}
		}
		catch
		{
			_panelBackingHas = false;
			_panelBackingTex = null;
		}
	}

	private static Sprite GetFirstPlaceFallbackSprite()
	{
		try
		{
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return null;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("TrophyEikthyr");
			if ((Object)(object)itemPrefab == (Object)null)
			{
				return null;
			}
			ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				return null;
			}
			return component.m_itemData.GetIcon();
		}
		catch
		{
			return null;
		}
	}

	private void EnsureHarmonyStillPatched(bool forceLog)
	{
		try
		{
			if (!AreCorePatchesPresent())
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"[Balanced Gliders] Detected missing Harmony patches. Re-applying.");
				ApplyAllHarmonyPatches();
			}
			else if (forceLog && _debugLogs != null && _debugLogs.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"[Balanced Gliders] Harmony patch check OK.");
			}
		}
		catch
		{
			ApplyAllHarmonyPatches();
		}
	}

	private bool AreCorePatchesPresent()
	{
		MethodInfo methodInfo = AccessTools.Method(typeof(GliderSystem), "CanGlide", (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			return false;
		}
		Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
		if (patchInfo == null)
		{
			return false;
		}
		bool flag = false;
		if (patchInfo.Prefixes != null)
		{
			for (int i = 0; i < patchInfo.Prefixes.Count; i++)
			{
				Patch val = patchInfo.Prefixes[i];
				if (val != null && val.owner == "Pix.BalancedGliders")
				{
					flag = true;
					break;
				}
			}
		}
		if (!flag && patchInfo.Postfixes != null)
		{
			for (int j = 0; j < patchInfo.Postfixes.Count; j++)
			{
				Patch val2 = patchInfo.Postfixes[j];
				if (val2 != null && val2.owner == "Pix.BalancedGliders")
				{
					flag = true;
					break;
				}
			}
		}
		if (!flag)
		{
			return false;
		}
		MethodInfo methodInfo2 = AccessTools.Method(typeof(ObjectDB), "Awake", (Type[])null, (Type[])null);
		if (methodInfo2 == null)
		{
			return false;
		}
		Patches patchInfo2 = Harmony.GetPatchInfo((MethodBase)methodInfo2);
		if (patchInfo2 == null)
		{
			return false;
		}
		bool result = false;
		if (patchInfo2.Postfixes != null)
		{
			for (int k = 0; k < patchInfo2.Postfixes.Count; k++)
			{
				Patch val3 = patchInfo2.Postfixes[k];
				if (val3 != null && val3.owner == "Pix.BalancedGliders")
				{
					result = true;
					break;
				}
			}
		}
		return result;
	}

	private static bool IsNetConnected()
	{
		try
		{
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			if (IsServer())
			{
				return true;
			}
			return ZNet.instance.IsConnected(ZNet.GetUID());
		}
		catch
		{
			return false;
		}
	}

	private static bool IsServer()
	{
		try
		{
			return (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer();
		}
		catch
		{
			return false;
		}
	}

	private static void DetectRoutedRpcInstanceChange()
	{
		try
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance == null)
			{
				_lastRoutedRpcInstance = null;
				_rpcsRegistered = false;
				_serverBroadcastedInitialConfig = false;
			}
			else if (instance != _lastRoutedRpcInstance)
			{
				_lastRoutedRpcInstance = instance;
				_rpcsRegistered = false;
				_serverBroadcastedInitialConfig = false;
			}
		}
		catch
		{
			_rpcsRegistered = false;
			_serverBroadcastedInitialConfig = false;
		}
	}

	private void HookServerConfigEvents()
	{
		try
		{
			Action broadcast = delegate
			{
				Runtime.LoadFromConfig();
				BroadcastServerConfig();
			};
			if (_enabled != null)
			{
				_enabled.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_cooldownSeconds != null)
			{
				_cooldownSeconds.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_dynamicEnabled != null)
			{
				_dynamicEnabled.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_dynamicBaseSeconds != null)
			{
				_dynamicBaseSeconds.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_dynamicPower != null)
			{
				_dynamicPower.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_dynamicMultiplier != null)
			{
				_dynamicMultiplier.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_dynamicMinSeconds != null)
			{
				_dynamicMinSeconds.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_dynamicMaxSeconds != null)
			{
				_dynamicMaxSeconds.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_dynamicShortHopThresholdSeconds != null)
			{
				_dynamicShortHopThresholdSeconds.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_showStatusEffect != null)
			{
				_showStatusEffect.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_debugLogs != null)
			{
				_debugLogs.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_leaderboardEnabled != null)
			{
				_leaderboardEnabled.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_leaderboardHotkey != null)
			{
				_leaderboardHotkey.SettingChanged += delegate
				{
					broadcast();
				};
			}
			if (_leaderboardMaxRows != null)
			{
				_leaderboardMaxRows.SettingChanged += delegate
				{
					broadcast();
				};
			}
		}
		catch
		{
		}
	}

	private static void RequestServerConfig()
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Expected O, but got Unknown
		try
		{
			if (ZRoutedRpc.instance != null && !((Object)(object)ZNet.instance == (Object)null))
			{
				ZRoutedRpc.instance.InvokeRoutedRPC("BG_RequestConfig", new object[1] { (object)new ZPackage() });
			}
		}
		catch
		{
		}
	}

	private static void BroadcastServerConfig()
	{
		try
		{
			if (IsServer() && ZRoutedRpc.instance != null)
			{
				ZPackage val = BuildConfigPackageFromRuntime();
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "BG_Config", new object[1] { val });
			}
		}
		catch
		{
		}
	}

	private static ZPackage BuildConfigPackageFromRuntime()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Expected I4, but got Unknown
		ZPackage val = new ZPackage();
		val.Write(Runtime.Enabled);
		val.Write(Runtime.CooldownSeconds);
		val.Write(Runtime.DynamicEnabled);
		val.Write(Runtime.DynamicBaseSeconds);
		val.Write(Runtime.DynamicPower);
		val.Write(Runtime.DynamicMultiplier);
		val.Write(Runtime.DynamicMinSeconds);
		val.Write(Runtime.DynamicMaxSeconds);
		val.Write(Runtime.DynamicShortHopThresholdSeconds);
		val.Write(Runtime.ShowStatusEffect);
		val.Write(Runtime.DebugLogs);
		val.Write(Runtime.LeaderboardEnabled);
		val.Write((int)Runtime.LeaderboardHotkey);
		val.Write(Runtime.LeaderboardMaxRows);
		return val;
	}

	private static void ApplyConfigPackageToRuntime(ZPackage pkg)
	{
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		Runtime.Enabled = pkg.ReadBool();
		Runtime.CooldownSeconds = pkg.ReadSingle();
		Runtime.DynamicEnabled = pkg.ReadBool();
		Runtime.DynamicBaseSeconds = pkg.ReadSingle();
		Runtime.DynamicPower = pkg.ReadSingle();
		Runtime.DynamicMultiplier = pkg.ReadSingle();
		Runtime.DynamicMinSeconds = pkg.ReadSingle();
		Runtime.DynamicMaxSeconds = pkg.ReadSingle();
		Runtime.DynamicShortHopThresholdSeconds = pkg.ReadSingle();
		Runtime.ShowStatusEffect = pkg.ReadBool();
		Runtime.DebugLogs = pkg.ReadBool();
		Runtime.LeaderboardEnabled = pkg.ReadBool();
		Runtime.LeaderboardHotkey = (KeyCode)pkg.ReadInt();
		Runtime.LeaderboardMaxRows = pkg.ReadInt();
		Runtime.HasServerConfig = true;
	}

	private static bool ShouldUseServerRuntime()
	{
		if (!IsNetConnected())
		{
			return false;
		}
		if (_serverAuthoritativeConfig == null || !_serverAuthoritativeConfig.Value)
		{
			return false;
		}
		if (IsServer())
		{
			return true;
		}
		if (_lockClientConfig != null && _lockClientConfig.Value)
		{
			return true;
		}
		return Runtime.HasServerConfig;
	}

	private static float ComputeCooldownSeconds(float glideSeconds)
	{
		bool num;
		if (!ShouldUseServerRuntime())
		{
			if (_dynamicEnabled == null)
			{
				goto IL_002e;
			}
			num = _dynamicEnabled.Value;
		}
		else
		{
			num = Runtime.DynamicEnabled;
		}
		if (num)
		{
			float num2 = Mathf.Max(0f, ShouldUseServerRuntime() ? Runtime.DynamicMinSeconds : ((_dynamicMinSeconds != null) ? _dynamicMinSeconds.Value : 10f));
			float num3 = Mathf.Max(num2, ShouldUseServerRuntime() ? Runtime.DynamicMaxSeconds : ((_dynamicMaxSeconds != null) ? _dynamicMaxSeconds.Value : 150f));
			float num4 = Mathf.Max(0f, ShouldUseServerRuntime() ? Runtime.DynamicShortHopThresholdSeconds : ((_dynamicShortHopThresholdSeconds != null) ? _dynamicShortHopThresholdSeconds.Value : 1f));
			if (glideSeconds <= num4)
			{
				return Mathf.Clamp(num2, num2, num3);
			}
			float num5 = Mathf.Max(0f, ShouldUseServerRuntime() ? Runtime.DynamicBaseSeconds : ((_dynamicBaseSeconds != null) ? _dynamicBaseSeconds.Value : 10f));
			float num6 = Mathf.Max(0.01f, ShouldUseServerRuntime() ? Runtime.DynamicPower : ((_dynamicPower != null) ? _dynamicPower.Value : 1.2f));
			float num7 = Mathf.Max(0f, ShouldUseServerRuntime() ? Runtime.DynamicMultiplier : ((_dynamicMultiplier != null) ? _dynamicMultiplier.Value : 2f));
			float num8 = num5 + Mathf.Pow(glideSeconds, num6) * num7;
			if (num8 < num2)
			{
				num8 = num2;
			}
			if (num8 > num3)
			{
				num8 = num3;
			}
			return num8;
		}
		goto IL_002e;
		IL_002e:
		float num9 = (ShouldUseServerRuntime() ? Runtime.CooldownSeconds : ((_cooldownSeconds != null) ? _cooldownSeconds.Value : 150f));
		return Mathf.Clamp(num9, 0f, 86400f);
	}

	private static void TryRegisterRpcs()
	{
		try
		{
			if (ZRoutedRpc.instance != null && !_rpcsRegistered)
			{
				ZRoutedRpc.instance.Register<ZPackage>("BG_RequestConfig", (Action<long, ZPackage>)RPC_Server_RequestConfig);
				ZRoutedRpc.instance.Register<ZPackage>("BG_GlideStart", (Action<long, ZPackage>)RPC_Server_GlideStart);
				ZRoutedRpc.instance.Register<ZPackage>("BG_GlideEnd", (Action<long, ZPackage>)RPC_Server_GlideEnd);
				ZRoutedRpc.instance.Register<ZPackage>("BG_Config", (Action<long, ZPackage>)RPC_Client_ReceiveConfig);
				ZRoutedRpc.instance.Register<ZPackage>("BG_SetCooldown", (Action<long, ZPackage>)RPC_Client_SetCooldown);
				ZRoutedRpc.instance.Register<ZPackage>("BG_LB_Req", (Action<long, ZPackage>)RPC_Server_RequestLeaderboard);
				ZRoutedRpc.instance.Register<ZPackage>("BG_LB_Recv", (Action<long, ZPackage>)RPC_Client_ReceiveLeaderboard);
				ZRoutedRpc.instance.Register<ZPackage>("BG_GlideResult", (Action<long, ZPackage>)RPC_Client_GlideResult);
				_rpcsRegistered = true;
			}
		}
		catch
		{
			_rpcsRegistered = false;
		}
	}

	private static void TryRegisterCommands()
	{
		//IL_0043: 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_003a: Expected O, but got Unknown
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Expected O, but got Unknown
		if (_commandsRegistered)
		{
			return;
		}
		try
		{
			object obj = <>c.<>9__115_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate
				{
					OutputClient(BuildStatusText(), hud: false);
				};
				<>c.<>9__115_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("bg_status", "Balanced Gliders: show effective status.", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj2 = <>c.<>9__115_1;
			if (obj2 == null)
			{
				ConsoleEvent val2 = delegate
				{
					if (!EffectiveLeaderboard)
					{
						OutputClient("Balanced Gliders: leaderboard is disabled.", hud: true);
					}
					else
					{
						_lbVisible = !_lbVisible;
						if (_lbVisible)
						{
							if (string.IsNullOrEmpty(_lbText))
							{
								_lbText = "Loading leaderboard...";
							}
							RequestLeaderboardIfClient();
						}
					}
				};
				<>c.<>9__115_1 = val2;
				obj2 = (object)val2;
			}
			new ConsoleCommand("bg_top", "Balanced Gliders: toggle leaderboard.", (ConsoleEvent)obj2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			_commandsRegistered = true;
		}
		catch
		{
			_commandsRegistered = true;
		}
	}

	private static void OutputClient(string text, bool hud)
	{
		try
		{
			if (!string.IsNullOrEmpty(text))
			{
				if (hud && (Object)(object)MessageHud.instance != (Object)null)
				{
					MessageHud.instance.ShowMessage((MessageType)1, text, 0, (Sprite)null, false);
				}
				if ((Object)(object)Chat.instance != (Object)null)
				{
					Chat.instance.SendText((Type)1, text);
				}
				if (EffectiveDebug)
				{
					Debug.Log((object)("[Balanced Gliders] " + text));
				}
			}
		}
		catch
		{
		}
	}

	private static string BuildStatusText()
	{
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			bool flag = IsNetConnected();
			bool flag2 = IsServer();
			bool flag3 = ShouldUseServerRuntime();
			return "[Balanced Gliders v0.8.1] status\n" + $"Connected={flag} Server={flag2}\n" + $"RPCsRegistered={_rpcsRegistered} HasServerConfig={Runtime.HasServerConfig} UseServerRuntime={flag3}\n" + $"Enabled={EffectiveEnabled} ShowSE={EffectiveShowSE}\n" + $"Leaderboard={EffectiveLeaderboard} Hotkey={EffectiveLeaderboardHotkey} MaxRows={EffectiveLeaderboardMaxRows}";
		}
		catch
		{
			return "[Balanced Gliders] status unavailable.";
		}
	}

	private static void RPC_Server_RequestConfig(long sender, ZPackage pkg)
	{
		try
		{
			if (IsServer())
			{
				Runtime.LoadFromConfig();
				ZPackage val = BuildConfigPackageFromRuntime();
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "BG_Config", new object[1] { val });
			}
		}
		catch
		{
		}
	}

	private static void RPC_Client_ReceiveConfig(long sender, ZPackage pkg)
	{
		try
		{
			if (!IsServer())
			{
				ApplyConfigPackageToRuntime(pkg);
			}
		}
		catch
		{
		}
	}

	private static void RPC_Server_GlideStart(long sender, ZPackage pkg)
	{
		//IL_006a: 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_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!IsServer() || !EffectiveEnabled)
			{
				return;
			}
			long num = 0L;
			try
			{
				num = pkg.ReadLong();
			}
			catch
			{
				num = 0L;
			}
			ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetPeer(sender) : null);
			if (val == null)
			{
				return;
			}
			ZDOID characterID = val.m_characterID;
			if (((ZDOID)(ref characterID)).IsNone())
			{
				return;
			}
			ZDO val2 = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(characterID) : null);
			if (val2 != null)
			{
				long networkTimeMs = GetNetworkTimeMs();
				long num2 = networkTimeMs;
				if (num > 0 && Math.Abs(num - networkTimeMs) <= 10000)
				{
					num2 = num;
				}
				val2.Set(ZdoKey_GlideStartMs, num2);
				if (EffectiveLeaderboard)
				{
					_glideTrackByZdo[characterID] = new GlideTrack
					{
						StartPos = val2.GetPosition(),
						StartMs = num2
					};
				}
			}
		}
		catch
		{
		}
	}

	private static void RPC_Server_GlideEnd(long sender, ZPackage pkg)
	{
		//IL_01bc: 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_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Expected O, but got Unknown
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!IsServer() || !EffectiveEnabled)
			{
				return;
			}
			long num = 0L;
			try
			{
				num = pkg.ReadLong();
			}
			catch
			{
				num = 0L;
			}
			ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetPeer(sender) : null);
			if (val == null)
			{
				return;
			}
			ZDOID characterID = val.m_characterID;
			if (((ZDOID)(ref characterID)).IsNone())
			{
				return;
			}
			ZDO val2 = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(characterID) : null);
			if (val2 == null)
			{
				return;
			}
			long networkTimeMs = GetNetworkTimeMs();
			long num2 = networkTimeMs;
			if (num > 0 && Math.Abs(num - networkTimeMs) <= 10000)
			{
				num2 = num;
			}
			long @long = val2.GetLong(ZdoKey_GlideStartMs, 0L);
			val2.Set(ZdoKey_GlideStartMs, 0L);
			float num3 = 0f;
			if (@long > 0 && num2 > @long)
			{
				num3 = (float)(num2 - @long) / 1000f;
			}
			if (num3 < 0.15f)
			{
				if (EffectiveLeaderboard)
				{
					_glideTrackByZdo.Remove(characterID);
				}
				return;
			}
			float num4 = ComputeCooldownSeconds(num3);
			long num5 = num2 + (long)(Mathf.Max(0f, num4) * 1000f);
			val2.Set(ZdoKey_CooldownEndMs, num5);
			try
			{
				ZPackage val3 = new ZPackage();
				val3.Write(num5);
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "BG_SetCooldown", new object[1] { val3 });
			}
			catch
			{
			}
			if (EffectiveLeaderboard)
			{
				UpdateLeaderboard_Server(sender, val, characterID, val2, num3);
			}
		}
		catch
		{
		}
	}

	private static void RPC_Client_SetCooldown(long sender, ZPackage pkg)
	{
		try
		{
			if (IsServer())
			{
				return;
			}
			long num = 0L;
			try
			{
				num = pkg.ReadLong();
			}
			catch
			{
				num = 0L;
			}
			if (num <= 0)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && ((Character)localPlayer).IsOwner())
			{
				ZDO zdo = GetZdo(localPlayer);
				if (zdo != null)
				{
					zdo.Set(ZdoKey_CooldownEndMs, num);
				}
			}
		}
		catch
		{
		}
	}

	private static void RPC_Server_RequestLeaderboard(long sender, ZPackage pkg)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Expected O, but got Unknown
		try
		{
			if (IsServer() && EffectiveLeaderboard)
			{
				string text = BuildLeaderboardText_Server(EffectiveLeaderboardMaxRows);
				ZPackage val = new ZPackage();
				val.Write(text ?? "");
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "BG_LB_Recv", new object[1] { val });
			}
		}
		catch
		{
		}
	}

	private static void RPC_Client_ReceiveLeaderboard(long sender, ZPackage pkg)
	{
		try
		{
			if (!IsServer())
			{
				string text = "";
				try
				{
					text = pkg.ReadString();
				}
				catch
				{
					text = "";
				}
				if (string.IsNullOrEmpty(text))
				{
					text = "No leaderboard data available.";
				}
				_lbText = text;
				_lbLastRequestAt = Time.unscaledTime;
			}
		}
		catch
		{
		}
	}

	private static void RPC_Client_GlideResult(long sender, ZPackage pkg)
	{
		try
		{
			if (!IsServer())
			{
				float num = 0f;
				bool flag = false;
				bool flag2 = false;
				try
				{
					num = pkg.ReadSingle();
				}
				catch
				{
					num = 0f;
				}
				try
				{
					flag = pkg.ReadBool();
				}
				catch
				{
					flag = false;
				}
				try
				{
					flag2 = pkg.ReadBool();
				}
				catch
				{
					flag2 = false;
				}
				_toastText = BuildToastText_Client(num, flag, flag2);
				_toastUntil = Time.unscaledTime + 0.05f;
			}
		}
		catch
		{
		}
	}

	private static void UpdateLeaderboard_Server(long senderUid, ZNetPeer peer, ZDOID zdoid, ZDO zdo, float airtimeSeconds)
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: 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_0057: 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_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: 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_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_0281: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Expected O, but got Unknown
		try
		{
			if (!IsServer() || peer == null || zdo == null || !_glideTrackByZdo.TryGetValue(zdoid, out var value))
			{
				return;
			}
			_glideTrackByZdo.Remove(zdoid);
			Vector3 position = zdo.GetPosition();
			Vector3 startPos = value.StartPos;
			float num = position.x - startPos.x;
			float num2 = position.z - startPos.z;
			float num3 = Mathf.Sqrt(num * num + num2 * num2);
			float num4 = Mathf.Max(0f, startPos.y - position.y);
			if (num3 < 0.5f)
			{
				return;
			}
			string name = SafePeerName(peer);
			string text = NormalizeNameKey(name);
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			long num5 = text.GetStableHashCode();
			if (num5 == 0)
			{
				num5 = senderUid;
			}
			if (num5 == 0)
			{
				return;
			}
			long networkTimeMs = GetNetworkTimeMs();
			float num6 = 0f;
			foreach (RecordEntry value4 in _recordsById.Values)
			{
				if (value4 != null)
				{
					string text2 = NormalizeNameKey(value4.Name);
					if (text2 == text && value4.BestDistance > num6)
					{
						num6 = value4.BestDistance;
					}
				}
			}
			if (!_recordsById.TryGetValue(num5, out var value2) || value2 == null)
			{
				value2 = new RecordEntry
				{
					Id = num5
				};
				_recordsById[num5] = value2;
			}
			value2.Name = name;
			value2.LatestDistance = num3;
			value2.LatestAirtime = airtimeSeconds;
			value2.LatestDrop = num4;
			value2.UpdatedAtMs = networkTimeMs;
			bool flag = num3 > num6 + 0.01f;
			if (flag)
			{
				value2.BestDistance = num3;
				value2.BestAirtime = airtimeSeconds;
				value2.BestDrop = num4;
			}
			float value3;
			bool flag2 = !_dailyBestById.TryGetValue(num5, out value3) || num3 > value3 + 0.01f;
			if (flag2)
			{
				_dailyBestById[num5] = num3;
			}
			_recordsDirty = true;
			_nextRecordsSaveAt = Time.unscaledTime + 2f;
			try
			{
				ZPackage val = new ZPackage();
				val.Write(num3);
				val.Write(flag2);
				val.Write(flag);
				ZRoutedRpc.instance.InvokeRoutedRPC(senderUid, "BG_GlideResult", new object[1] { val });
			}
			catch
			{
			}
		}
		catch
		{
		}
	}

	private static string BuildLeaderboardText_Server(int topN)
	{
		try
		{
			if (!IsServer())
			{
				return "Balanced Gliders: leaderboard is server-only.";
			}
			if (_recordsById.Count == 0)
			{
				return "(no records yet)";
			}
			int num = Mathf.Clamp(topN, 5, 100);
			Dictionary<string, RecordEntry> dictionary = new Dictionary<string, RecordEntry>(StringComparer.OrdinalIgnoreCase);
			foreach (RecordEntry value4 in _recordsById.Values)
			{
				if (value4 != null)
				{
					string text = (string.IsNullOrEmpty(value4.Name) ? "Someone" : value4.Name);
					string text2 = NormalizeNameKey(text);
					if (string.IsNullOrEmpty(text2))
					{
						text2 = text;
					}
					if (!dictionary.TryGetValue(text2, out var value) || value == null)
					{
						dictionary[text2] = value4;
					}
					else if (value4.BestDistance > value.BestDistance + 0.01f || (Mathf.Abs(value4.BestDistance - value.BestDistance) <= 0.01f && value4.UpdatedAtMs > value.UpdatedAtMs))
					{
						dictionary[text2] = value4;
					}
				}
			}
			List<RecordEntry> list = new List<RecordEntry>(dictionary.Values);
			list.Sort((RecordEntry a, RecordEntry b) => b.BestDistance.CompareTo(a.BestDistance));
			int num2 = Mathf.Min(num, list.Count);
			StringBuilder stringBuilder = new StringBuilder(1024);
			for (int i = 0; i < num2; i++)
			{
				RecordEntry recordEntry = list[i];
				string value2 = (string.IsNullOrEmpty(recordEntry.Name) ? "Someone" : recordEntry.Name);
				string value3 = (i + 1).ToString(CultureInfo.InvariantCulture) + ". ";
				stringBuilder.Append(value3).Append(value2).Append(" — ")
					.Append(recordEntry.BestDistance.ToString("0", CultureInfo.InvariantCulture))
					.Append("m | ")
					.Append("Drop ")
					.Append(recordEntry.BestDrop.ToString("0", CultureInfo.InvariantCulture))
					.Append("m | ")
					.Append(recordEntry.BestAirtime.ToString("0.0", CultureInfo.InvariantCulture))
					.Append("s")
					.Append("  (Latest ")
					.Append(recordEntry.LatestDistance.ToString("0", CultureInfo.InvariantCulture))
					.Append("m | ")
					.Append("Drop ")
					.Append(recordEntry.LatestDrop.ToString("0", CultureInfo.InvariantCulture))
					.Append("m | ")
					.Append(recordEntry.LatestAirtime.ToString("0.0", CultureInfo.InvariantCulture))
					.Append("s)")
					.Append('\n');
			}
			return stringBuilder.ToString().TrimEnd(new char[1] { '\n' });
		}
		catch
		{
			return "No leaderboard data available.";
		}
	}

	private static void LoadRecordsFromDisk()
	{
		try
		{
			if (string.IsNullOrEmpty(_recordsPath) || !File.Exists(_recordsPath))
			{
				return;
			}
			string[] array = File.ReadAllLines(_recordsPath);
			if (array == null || array.Length == 0)
			{
				return;
			}
			_recordsById.Clear();
			foreach (string text in array)
			{
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				List<string> list = SplitPipe(text);
				if (list != null && list.Count >= 9 && long.TryParse(list[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result != 0)
				{
					RecordEntry recordEntry = new RecordEntry();
					recordEntry.Id = result;
					recordEntry.Name = UnescapeField(list[1]);
					recordEntry.BestDistance = ParseFloat(list[2]);
					recordEntry.BestAirtime = ParseFloat(list[3]);
					recordEntry.BestDrop = ParseFloat(list[4]);
					recordEntry.LatestDistance = ParseFloat(list[5]);
					recordEntry.LatestAirtime = ParseFloat(list[6]);
					recordEntry.LatestDrop = ParseFloat(list[7]);
					if (!long.TryParse(list[8], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2))
					{
						result2 = 0L;
					}
					recordEntry.UpdatedAtMs = result2;
					_recordsById[result] = recordEntry;
				}
			}
		}
		catch
		{
		}
	}

	private static void SaveRecordsToDisk()
	{
		try
		{
			if (string.IsNullOrEmpty(_recordsPath))
			{
				return;
			}
			Dictionary<string, RecordEntry> dictionary = new Dictionary<string, RecordEntry>(StringComparer.OrdinalIgnoreCase);
			foreach (RecordEntry value3 in _recordsById.Values)
			{
				if (value3 != null)
				{
					string text = (string.IsNullOrEmpty(value3.Name) ? "Someone" : value3.Name);
					string text2 = NormalizeNameKey(text);
					if (string.IsNullOrEmpty(text2))
					{
						text2 = text;
					}
					if (!dictionary.TryGetValue(text2, out var value) || value == null || value3.BestDistance > value.BestDistance + 0.01f || (Mathf.Abs(value3.BestDistance - value.BestDistance) <= 0.01f && value3.UpdatedAtMs > value.UpdatedAtMs))
					{
						dictionary[text2] = value3;
					}
				}
			}
			StringBuilder stringBuilder = new StringBuilder(4096);
			foreach (KeyValuePair<string, RecordEntry> item in dictionary)
			{
				RecordEntry value2 = item.Value;
				if (value2 != null)
				{
					stringBuilder.Append(value2.Id.ToString(CultureInfo.InvariantCulture)).Append('|');
					stringBuilder.Append(EscapeField(value2.Name)).Append('|');
					stringBuilder.Append(value2.BestDistance.ToString("R", CultureInfo.InvariantCulture)).Append('|');
					stringBuilder.Append(value2.BestAirtime.ToString("R", CultureInfo.InvariantCulture)).Append('|');
					stringBuilder.Append(value2.BestDrop.ToString("R", CultureInfo.InvariantCulture)).Append('|');
					stringBuilder.Append(value2.LatestDistance.ToString("R", CultureInfo.InvariantCulture)).Append('|');
					stringBuilder.Append(value2.LatestAirtime.ToString("R", CultureInfo.InvariantCulture)).Append('|');
					stringBuilder.Append(value2.LatestDrop.ToString("R", CultureInfo.InvariantCulture)).Append('|');
					stringBuilder.Append(value2.UpdatedAtMs.ToString(CultureInfo.InvariantCulture));
					stringBuilder.Append('\n');
				}
			}
			File.WriteAllText(_recordsPath, stringBuilder.ToString());
			_recordsDirty = false;
		}
		catch
		{
		}
	}

	private static bool IsOnCooldown(Player p, out float remainingSeconds)
	{
		long cooldownEndMs = GetCooldownEndMs(p);
		long networkTimeMs = GetNetworkTimeMs();
		long num = cooldownEndMs - networkTimeMs;
		remainingSeconds = ((num > 0) ? ((float)num / 1000f) : 0f);
		return num > 0;
	}

	private static long GetCooldownEndMs(Player p)
	{
		ZDO zdo = GetZdo(p);
		if (zdo == null)
		{
			return 0L;
		}
		return zdo.GetLong(ZdoKey_CooldownEndMs, 0L);
	}

	private static bool WasGliding(Player p)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		if (TryGetValidZdoId(p, out var uid))
		{
			if (_wasGlidingByZdo.TryGetValue(uid, out var value))
			{
				return value;
			}
			return false;
		}
		long playerIdSafe = GetPlayerIdSafe(p);
		if (playerIdSafe != 0 && _wasGlidingByPlayerId.TryGetValue(playerIdSafe, out var value2))
		{
			return value2;
		}
		return false;
	}

	private static void MarkGliding(Player p, bool gliding)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		if (TryGetValidZdoId(p, out var uid))
		{
			_wasGlidingByZdo[uid] = gliding;
			return;
		}
		long playerIdSafe = GetPlayerIdSafe(p);
		if (playerIdSafe != 0)
		{
			_wasGlidingByPlayerId[playerIdSafe] = gliding;
		}
	}

	private static long GetPlayerIdSafe(Player p)
	{
		try
		{
			return p.GetPlayerID();
		}
		catch
		{
			return 0L;
		}
	}

	private static bool TryGetValidZdoId(Player p, out ZDOID uid)
	{
		//IL_0002: 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_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		uid = default(ZDOID);
		try
		{
			ZDO zdo = GetZdo(p);
			if (zdo == null)
			{
				return false;
			}
			uid = zdo.m_uid;
			if (((ZDOID)(ref uid)).Equals(default(ZDOID)))
			{
				return false;
			}
			return true;
		}
		catch
		{
			return false;
		}
	}

	private static ZDO GetZdo(Player p)
	{
		try
		{
			ZNetView val = _frNView.Invoke((Character)(object)p);
			return ((Object)(object)val != (Object)null) ? val.GetZDO() : null;
		}
		catch
		{
			return null;
		}
	}

	private static long GetNetworkTimeMs()
	{
		double num = Time.realtimeSinceStartupAsDouble;
		try
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance != (Object)null)
			{
				num = instance.GetTimeSeconds();
			}
		}
		catch
		{
		}
		return (long)(num * 1000.0);
	}

	private static string FormatSeconds(float seconds)
	{
		if (seconds < 0f)
		{
			seconds = 0f;
		}
		int num = (int)Mathf.Ceil(seconds);
		int num2 = num / 3600;
		int num3 = num % 3600 / 60;
		int num4 = num % 60;
		if (num2 > 0)
		{
			return num2 + ":" + num3.ToString("00") + ":" + num4.ToString("00");
		}
		if (num3 > 0)
		{
			return num3 + ":" + num4.ToString("00");
		}
		return "0:" + num4.ToString("00");
	}

	private static bool TryForceSetCooldownIcon(StatusEffect target)
	{
		if ((Object)(object)target == (Object)null)
		{
			return false;
		}
		try
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			StatusEffect statusEffect = instance.GetStatusEffect("SlowFall".GetStableHashCode());
			if ((Object)(object)statusEffect != (Object)null && (Object)(object)statusEffect.m_icon != (Object)null)
			{
				target.m_icon = statusEffect.m_icon;
				return true;
			}
			StatusEffect statusEffect2 = instance.GetStatusEffect("SE_FeatherFall".GetStableHashCode());
			if ((Object)(object)statusEffect2 != (Object)null && (Object)(object)statusEffect2.m_icon != (Object)null)
			{
				target.m_icon = statusEffect2.m_icon;
				return true;
			}
			StatusEffect statusEffect3 = instance.GetStatusEffect("Wet".GetStableHashCode());
			if ((Object)(object)statusEffect3 != (Object)null && (Object)(object)statusEffect3.m_icon != (Object)null)
			{
				target.m_icon = statusEffect3.m_icon;
				return true;
			}
		}
		catch
		{
		}
		return false;
	}

	private static void EnsureCooldownSEPrefab()
	{
		if ((Object)(object)_cooldownSEPrefab != (Object)null)
		{
			TryForceSetCooldownIcon(_cooldownSEPrefab);
			return;
		}
		try
		{
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(CooldownSEHash);
				if ((Object)(object)statusEffect != (Object)null)
				{
					_cooldownSEPrefab = statusEffect;
					TryForceSetCooldownIcon(_cooldownSEPrefab);
					return;
				}
			}
		}
		catch
		{
		}
		SE_GliderCooldown sE_GliderCooldown = ScriptableObject.CreateInstance<SE_GliderCooldown>();
		((Object)sE_GliderCooldown).name = "SE_BalancedGliders_Cooldown";
		((StatusEffect)sE_GliderCooldown).m_name = "Glider Cooldown";
		((StatusEffect)sE_GliderCooldown).m_tooltip = "Glider is recharging.";
		((StatusEffect)sE_GliderCooldown).m_ttl = 999999f;
		TryForceSetCooldownIcon((StatusEffect)(object)sE_GliderCooldown);
		if ((Object)(object)((StatusEffect)sE_GliderCooldown).m_icon == (Object)null)
		{
			try
			{
				if ((Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_StatusEffects != null)
				{
					foreach (StatusEffect statusEffect2 in ObjectDB.instance.m_StatusEffects)
					{
						if ((Object)(object)statusEffect2 != (Object)null && (Object)(object)statusEffect2.m_icon != (Object)null)
						{
							((StatusEffect)sE_GliderCooldown).m_icon = statusEffect2.m_icon;
							break;
						}
					}
				}
			}
			catch
			{
			}
		}
		_cooldownSEPrefab = (StatusEffect)(object)sE_GliderCooldown;
	}

	private static void EnsureCooldownStatusEffect(Player p)
	{
		if ((Object)(object)p == (Object)null || !EffectiveShowSE)
		{
			return;
		}
		SEMan sEMan = ((Character)p).GetSEMan();
		if (sEMan == null)
		{
			return;
		}
		try
		{
			EnsureCooldownSEPrefab();
			if ((Object)(object)ObjectDB.instance != (Object)null && (Object)(object)ObjectDB.instance.GetStatusEffect(CooldownSEHash) == (Object)null)
			{
				EnsureSEInObjectDB(ObjectDB.instance);
			}
			if (!sEMan.HaveStatusEffect(CooldownSEHash))
			{
				sEMan.AddStatusEffect(CooldownSEHash, true, 0, 0f);
			}
		}
		catch
		{
		}
	}

	private static void RemoveCooldownStatusEffectIfPresent(Player p)
	{
		if ((Object)(object)p == (Object)null)
		{
			return;
		}
		SEMan sEMan = ((Character)p).GetSEMan();
		if (sEMan == null)
		{
			return;
		}
		try
		{
			if (sEMan.HaveStatusEffect(CooldownSEHash))
			{
				sEMan.RemoveStatusEffect(CooldownSEHash, true);
			}
		}
		catch
		{
		}
	}

	private static void EnsureSEInObjectDB(ObjectDB db)
	{
		try
		{
			if ((Object)(object)db == (Object)null)
			{
				return;
			}
			StatusEffect statusEffect = db.GetStatusEffect(CooldownSEHash);
			if ((Object)(object)statusEffect != (Object)null)
			{
				_cooldownSEPrefab = statusEffect;
				TryForceSetCooldownIcon(statusEffect);
				return;
			}
			EnsureCooldownSEPrefab();
			TryForceSetCooldownIcon(_cooldownSEPrefab);
			if ((Object)(object)_cooldownSEPrefab != (Object)null && db.m_StatusEffects != null && !db.m_StatusEffects.Contains(_cooldownSEPrefab))
			{
				db.m_StatusEffects.Add(_cooldownSEPrefab);
			}
		}
		catch
		{
		}
	}

	private static bool IsTypingOrConsoleOpen()
	{
		try
		{
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return true;
			}
			if (Console.IsVisible())
			{
				return true;
			}
		}
		catch
		{
		}
		return false;
	}

	private static void ShowHud(MessageType type, string text)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!((Object)(object)MessageHud.instance == (Object)null) && !string.IsNullOrEmpty(text))
			{
				MessageHud.instance.ShowMessage(type, text, 0, (Sprite)null, false);
			}
		}
		catch
		{
		}
	}

	private static void RequestLeaderboardIfClient()
	{
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Expected O, but got Unknown
		try
		{
			if (!EffectiveLeaderboard)
			{
				return;
			}
			if (IsServer())
			{
				_lbText = BuildLeaderboardText_Server(EffectiveLeaderboardMaxRows);
			}
			else if (!(Time.unscaledTime - _lbLastRequestAt < 0.35f))
			{
				_lbLastRequestAt = Time.unscaledTime;
				if (ZRoutedRpc.instance != null)
				{
					ZRoutedRpc.instance.InvokeRoutedRPC("BG_LB_Req", new object[1] { (object)new ZPackage() });
				}
			}
		}
		catch
		{
		}
	}

	private static string BuildToastText_Client(float dist, bool newDaily, bool newAllTime)
	{
		string pipeSeparated;
		string fallback;
		string newValue;
		if (newAllTime)
		{
			pipeSeparated = ((_toastVariantsAllTimePB != null) ? _toastVariantsAllTimePB.Value : "");
			fallback = $"ALL-TIME PB! {dist:0}m";
			newValue = "All-Time PB";
		}
		else if (newDaily)
		{
			pipeSeparated = ((_toastVariantsDailyPB != null) ? _toastVariantsDailyPB.Value : "");
			fallback = $"Daily PB! {dist:0}m";
			newValue = "Daily PB";
		}
		else
		{
			pipeSeparated = ((_toastVariantsNormal != null) ? _toastVariantsNormal.Value : "");
			fallback = $"You traveled {dist:0}m";
			newValue = "Glide Complete";
		}
		string text = ChooseVariant(pipeSeparated, fallback);
		string newValue2 = "Viking";
		try
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && !string.IsNullOrEmpty(localPlayer.GetPlayerName()))
			{
				newValue2 = localPlayer.GetPlayerName();
			}
		}
		catch
		{
		}
		return text.Replace("{dist}", dist.ToString("0", CultureInfo.InvariantCulture)).Replace("{dist1}", dist.ToString("0.0", CultureInfo.InvariantCulture)).Replace("{name}", newValue2)
			.Replace("{when}", newValue);
	}

	private static string ChooseVariant(string pipeSeparated, string fallback)
	{
		if (string.IsNullOrEmpty(pipeSeparated))
		{
			return fallback;
		}
		string[] array = pipeSeparated.Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries);
		if (array == null || array.Length == 0)
		{
			return fallback;
		}
		int num = Random.Range(0, array.Length);
		string text = ((array[num] != null) ? array[num].Trim() : "");
		return string.IsNullOrEmpty(text) ? fallback : text;
	}

	private static string StripRichText(string s)
	{
		if (string.IsNullOrEmpty(s))
		{
			return "";
		}
		StringBuilder stringBuilder = new StringBuilder(s.Length);
		bool flag = false;
		foreach (char c in s)
		{
			switch (c)
			{
			case '<':
				flag = true;
				continue;
			case '>':
				flag = false;
				continue;
			}
			if (!flag)
			{
				stringBuilder.Append(c);
			}
		}
		return stringBuilder.ToString();
	}

	private static string NormalizeNameKey(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return "";
		}
		name = StripRichText(name);
		name = name.Trim();
		name = name.Replace("\t", " ");
		name = name.Replace("|", " ");
		while (name.Contains("  "))
		{
			name = name.Replace("  ", " ");
		}
		return name.ToLowerInvariant();
	}

	private static string SafePeerName(ZNetPeer peer)
	{
		try
		{
			if (peer == null)
			{
				return "Someone";
			}
			string playerName = peer.m_playerName;
			if (!string.IsNullOrEmpty(playerName))
			{
				return playerName;
			}
		}
		catch
		{
		}
		return "Someone";
	}

	private static string EscapeField(string s)
	{
		if (s == null)
		{
			return "";
		}
		return s.Replace("\\", "\\\\").Replace("|", "\\|").Replace("\n", " ")
			.Replace("\r", " ");
	}

	private static string UnescapeField(string s)
	{
		if (s == null)
		{
			return "";
		}
		StringBuilder stringBuilder = new StringBuilder(s.Length);
		bool flag = false;
		foreach (char c in s)
		{
			if (!flag)
			{
				if (c == '\\')
				{
					flag = true;
				}
				else
				{
					stringBuilder.Append(c);
				}
			}
			else
			{
				stringBuilder.Append(c);
				flag = false;
			}
		}
		return stringBuilder.ToString();
	}

	private static List<string> SplitPipe(string line)
	{
		if (line == null)
		{
			return null;
		}
		List<string> list = new List<string>(12);
		StringBuilder stringBuilder = new StringBuilder(line.Length);
		bool flag = false;
		foreach (char c in line)
		{
			if (!flag)
			{
				switch (c)
				{
				case '\\':
					flag = true;
					break;
				case '|':
					list.Add(stringBuilder.ToString());
					stringBuilder.Length = 0;
					break;
				default:
					stringBuilder.Append(c);
					break;
				}
			}
			else
			{
				stringBuilder.Append(c);
				flag = false;
			}
		}
		list.Add(stringBuilder.ToString());
		return list;
	}

	private static float ParseFloat(string s)
	{
		if (float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
		{
			return result;
		}
		return 0f;
	}
}