Decompiled source of TightBeam v2.1.1

TightBeam.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne;
using Il2CppScheduleOne.AvatarFramework;
using Il2CppScheduleOne.AvatarFramework.Equipping;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Equipping;
using Il2CppScheduleOne.Networking;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.Tools;
using Il2CppScheduleOne.UI.Phone;
using Il2CppSteamworks;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using TightBeam;
using TightBeam.Bridge;
using TightBeam.Config;
using TightBeam.Lighting;
using TightBeam.Net;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "TightBeam", "2.1.1", "DooDesch", "https://github.com/DooDesch-Mods/ScheduleOne-TightBeam")]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("DooDesch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © DooDesch")]
[assembly: AssemblyFileVersion("2.1.1.0")]
[assembly: AssemblyInformationalVersion("2.1.1+6a27b2537a99a676ae7a40dc3b689df274b26d72")]
[assembly: AssemblyProduct("TightBeam")]
[assembly: AssemblyTitle("TightBeam")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("2.1.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TightBeam
{
	public sealed class Core : MelonMod
	{
		private bool _inMain;

		private bool _patched;

		private bool _wasEnabled = true;

		public static Instance Log { get; private set; }

		public override void OnInitializeMelon()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			Log = ((MelonBase)this).LoggerInstance;
			TightBeamPreferences.Initialize();
			FlashlightController.Instance.InitFromPrefs();
			BridgeHost.Install();
			BeamPostBuilder.Start();
			Log.Msg($"TightBeam initialized. Enabled={TightBeamPreferences.Enabled}. On/off follows the game flashlight; hold {TightBeamPreferences.FocusModifierKey} + mouse wheel = focus/Pegel.");
		}

		public override void OnSceneWasInitialized(int buildIndex, string sceneName)
		{
			_inMain = sceneName == "Main";
			if (_inMain && !_patched)
			{
				((MelonBase)this).HarmonyInstance.PatchAll(typeof(Core).Assembly);
				_patched = true;
				Log.Msg("TightBeam: hotbar ALT+scroll guard applied.");
			}
			BeamBoard.EndSession();
			RemoteBeams.NewSession();
		}

		public override void OnUpdate()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!TightBeamPreferences.Enabled || !_inMain)
			{
				return;
			}
			FlashlightController instance = FlashlightController.Instance;
			instance.SyncOnFromGame();
			if (instance.IsOn)
			{
				if (Input.GetKey(TightBeamPreferences.FocusModifierKey))
				{
					instance.UpdateFocusScroll(GameInput.MouseScrollDelta, Time.deltaTime);
				}
				else
				{
					instance.ResetFocusScrollVelocity();
				}
			}
		}

		public override void OnLateUpdate()
		{
			FlashlightController instance = FlashlightController.Instance;
			if (!TightBeamPreferences.Enabled)
			{
				if (_wasEnabled)
				{
					_wasEnabled = false;
					instance.DisableRig();
					RemoteBeams.DisableAll();
				}
				BeamBoard.Tick(modEnabled: false);
				return;
			}
			_wasEnabled = true;
			if (!_inMain)
			{
				instance.DisableRig();
				RemoteBeams.DisableAll();
				BeamBoard.Tick(modEnabled: false);
			}
			else
			{
				instance.EnsureRig();
				instance.Follow();
				instance.Tick(Time.deltaTime);
				BeamBoard.Tick(modEnabled: true);
				RemoteBeams.Tick(Time.deltaTime);
			}
		}
	}
}
namespace TightBeam.Patches
{
	[HarmonyPatch(typeof(PlayerInventory), "UpdateHotbarSelection")]
	internal static class HotbarScrollGuard
	{
		private static bool Prefix()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (!TightBeamPreferences.Enabled)
			{
				return true;
			}
			if (Input.GetKey(TightBeamPreferences.FocusModifierKey) && GameInput.MouseScrollDelta != 0f)
			{
				return false;
			}
			return true;
		}
	}
}
namespace TightBeam.Net
{
	internal static class BeamBoard
	{
		private const float PublishDebounce = 0.2f;

		private const float SweepWhenCallbackUnproven = 1f;

		private const float SweepWhenCallbackWorks = 5f;

		private static readonly Dictionary<ulong, BeamPost> _posts = new Dictionary<ulong, BeamPost>();

		private static Callback<LobbyDataUpdate_t> _dataCallback;

		private static Action _onLobbyChange;

		private static BeamPost _lastPublished;

		private static bool _hasPublished;

		private static bool _withdrawPending;

		private static float _nextPublishAt;

		private static float _nextRescanAt;

		private static float _writeBackoff;

		private static float _writeDelay;

		private static bool _warnedWrite;

		private static ulong _boundLobby;

		private static bool _callbackProven;

		private static bool _verifiedWrite;

		private const float BackoffMin = 0.5f;

		private const float BackoffMax = 15f;

		private static readonly ulong[] _noIds = new ulong[0];

		private static readonly HashSet<ulong> _seen = new HashSet<ulong>();

		private static readonly List<ulong> _gone = new List<ulong>();

		internal static int KnownCount => _posts.Count;

		internal static int ReadCount { get; private set; }

		internal static int WriteCount { get; private set; }

		private static ulong LobbyId
		{
			get
			{
				try
				{
					Lobby instance = Singleton<Lobby>.Instance;
					if ((Object)(object)instance == (Object)null || !instance.IsInLobby)
					{
						return 0uL;
					}
					return instance.LobbyID;
				}
				catch
				{
					return 0uL;
				}
			}
		}

		internal static bool Available => LobbyId != 0;

		internal static void Tick(bool modEnabled)
		{
			ulong lobbyId = LobbyId;
			if (lobbyId == 0L)
			{
				if (_boundLobby != 0L)
				{
					Reset();
				}
				return;
			}
			if (lobbyId != _boundLobby)
			{
				Reset();
				_boundLobby = lobbyId;
				Bind();
				ReadAll(lobbyId);
			}
			if (modEnabled && TightBeamPreferences.SyncMyBeam)
			{
				_withdrawPending = false;
				Publish(lobbyId);
			}
			else if (_hasPublished || _withdrawPending)
			{
				Withdraw(lobbyId);
			}
			if (modEnabled && Time.time >= _nextRescanAt)
			{
				_nextRescanAt = Time.time + (_callbackProven ? 5f : 1f);
				ReadAll(lobbyId);
			}
		}

		private static void Bind()
		{
			if (_dataCallback == null)
			{
				try
				{
					_dataCallback = Callback<LobbyDataUpdate_t>.Create(DispatchDelegate<LobbyDataUpdate_t>.op_Implicit((Action<LobbyDataUpdate_t>)OnLobbyData));
					Instance log = Core.Log;
					if (log != null)
					{
						log.Msg("[board] lobby-data callback registered.");
					}
				}
				catch (Exception ex)
				{
					Instance log2 = Core.Log;
					if (log2 != null)
					{
						log2.Warning("[board] no lobby-data callback on this build (" + ex.GetType().Name + "); beam updates come from the periodic sweep instead.");
					}
				}
			}
			if (_onLobbyChange != null)
			{
				return;
			}
			try
			{
				Lobby instance = Singleton<Lobby>.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					_onLobbyChange = OnLobbyChange;
					instance.OnLobbyChange += Action.op_Implicit(_onLobbyChange);
				}
			}
			catch (Exception ex2)
			{
				Instance log3 = Core.Log;
				if (log3 != null)
				{
					log3.Warning("[board] lobby-change hook failed: " + ex2.Message);
				}
			}
		}

		internal static void EndSession()
		{
			_posts.Clear();
			if (_hasPublished)
			{
				_withdrawPending = true;
			}
		}

		internal static void Reset()
		{
			_posts.Clear();
			_hasPublished = false;
			_withdrawPending = false;
			_verifiedWrite = false;
			_nextPublishAt = 0f;
			_nextRescanAt = 0f;
			_writeBackoff = 0f;
			_writeDelay = 0f;
			_boundLobby = 0uL;
			_warnedWrite = false;
		}

		internal static bool TryGet(ulong steamId, out BeamPost post)
		{
			return _posts.TryGetValue(steamId, out post);
		}

		internal static ulong[] PostedIds()
		{
			if (_posts.Count == 0)
			{
				return _noIds;
			}
			ulong[] array = new ulong[_posts.Count];
			_posts.Keys.CopyTo(array, 0);
			return array;
		}

		private static void OnLobbyChange()
		{
			ulong lobbyId = LobbyId;
			if (lobbyId != 0L)
			{
				ReadAll(lobbyId);
			}
		}

		private static void OnLobbyData(LobbyDataUpdate_t e)
		{
			//IL_0022: 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)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!_callbackProven)
				{
					_callbackProven = true;
					Instance log = Core.Log;
					if (log != null)
					{
						log.Msg("[board] lobby-data callback is live; sweeping less often now.");
					}
				}
				if (e.m_ulSteamIDLobby == _boundLobby && e.m_ulSteamIDMember != e.m_ulSteamIDLobby)
				{
					ReadOne(e.m_ulSteamIDLobby, e.m_ulSteamIDMember);
				}
			}
			catch
			{
			}
		}

		private static void ReadAll(ulong lobby)
		{
			//IL_0012: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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)
			try
			{
				CSteamID val = default(CSteamID);
				((CSteamID)(ref val))..ctor(lobby);
				_seen.Clear();
				int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(val);
				for (int i = 0; i < numLobbyMembers; i++)
				{
					CSteamID lobbyMemberByIndex = SteamMatchmaking.GetLobbyMemberByIndex(val, i);
					_seen.Add(lobbyMemberByIndex.m_SteamID);
					ReadOne(lobby, lobbyMemberByIndex.m_SteamID);
				}
				_gone.Clear();
				foreach (ulong key in _posts.Keys)
				{
					if (!_seen.Contains(key))
					{
						_gone.Add(key);
					}
				}
				for (int j = 0; j < _gone.Count; j++)
				{
					_posts.Remove(_gone[j]);
				}
			}
			catch (Exception ex)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("[board] read failed: " + ex.Message);
				}
			}
		}

		private static void ReadOne(ulong lobby, ulong member)
		{
			//IL_0017: 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)
			try
			{
				if (member == PlayerIdentity.LocalSteamId())
				{
					_posts.Remove(member);
					return;
				}
				string lobbyMemberData = SteamMatchmaking.GetLobbyMemberData(new CSteamID(lobby), new CSteamID(member), "doodesch_tightbeam");
				ReadCount++;
				BeamPost p;
				if (string.IsNullOrEmpty(lobbyMemberData))
				{
					_posts.Remove(member);
				}
				else if (BeamWire.TryDecode(lobbyMemberData, out p))
				{
					_posts[member] = p;
				}
				else
				{
					_posts.Remove(member);
				}
			}
			catch
			{
			}
		}

		private static void Publish(ulong lobby)
		{
			//IL_0064: 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)
			if (Time.time < _nextPublishAt)
			{
				return;
			}
			BeamPost beamPost = BeamPostBuilder.Current();
			if (_hasPublished && beamPost.SameAs(_lastPublished))
			{
				return;
			}
			string value = BeamWire.Encode(beamPost);
			if (!Write(lobby, value))
			{
				return;
			}
			_lastPublished = beamPost;
			_hasPublished = true;
			_nextPublishAt = Time.time + 0.2f;
			if (_verifiedWrite)
			{
				return;
			}
			_verifiedWrite = true;
			try
			{
				if (string.IsNullOrEmpty(SteamMatchmaking.GetLobbyMemberData(new CSteamID(lobby), new CSteamID(PlayerIdentity.LocalSteamId()), "doodesch_tightbeam")))
				{
					Instance log = Core.Log;
					if (log != null)
					{
						log.Warning("[board] our beam did not stick in the lobby - another mod may have used up the member-data slots. Others will see default cones.");
					}
				}
			}
			catch
			{
			}
		}

		private static void Withdraw(ulong lobby)
		{
			_withdrawPending = true;
			if (Write(lobby, ""))
			{
				_hasPublished = false;
				_withdrawPending = false;
			}
		}

		private static bool Write(ulong lobby, string value)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < _writeBackoff)
			{
				return false;
			}
			try
			{
				SteamMatchmaking.SetLobbyMemberData(new CSteamID(lobby), "doodesch_tightbeam", value);
				if (_warnedWrite)
				{
					_warnedWrite = false;
					Instance log = Core.Log;
					if (log != null)
					{
						log.Msg("[board] beam sharing recovered.");
					}
				}
				_writeBackoff = 0f;
				_writeDelay = 0f;
				WriteCount++;
				return true;
			}
			catch (Exception ex)
			{
				_writeDelay = ((_writeDelay <= 0f) ? 0.5f : Mathf.Min(15f, _writeDelay * 2f));
				_writeBackoff = Time.time + _writeDelay;
				if (!_warnedWrite)
				{
					_warnedWrite = true;
					Instance log2 = Core.Log;
					if (log2 != null)
					{
						log2.Warning("[board] beam write failed, backing off: " + ex.Message);
					}
				}
				return false;
			}
		}
	}
	internal static class BeamPostBuilder
	{
		private static int _fxSeq;

		private static FxKind _fxKind;

		private static int _fxA;

		private static int _fxB;

		private static int _fxC;

		private static int _fxSeed;

		private static bool _hooked;

		internal static void Start()
		{
			if (!_hooked)
			{
				_hooked = true;
				FlashlightController.Instance.FxRaised += OnFxRaised;
			}
		}

		internal static BeamPost Current()
		{
			//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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			FlashlightController instance = FlashlightController.Instance;
			Color wireColor = instance.WireColor;
			return new BeamPost
			{
				On = instance.IsOn,
				I100 = Mathf.RoundToInt(Mathf.Max(0f, instance.WireIntensity) * 100f),
				R10 = Mathf.RoundToInt(Mathf.Clamp(instance.WireRange, 2f, 60f) * 10f),
				A10 = Mathf.RoundToInt(Mathf.Clamp(instance.WireSpotAngle, 8f, 90f) * 10f),
				Rgb24 = ((Byte(wireColor.r) << 16) | (Byte(wireColor.g) << 8) | Byte(wireColor.b)),
				FxSeq = _fxSeq,
				Fx = _fxKind,
				FxA = _fxA,
				FxB = _fxB,
				FxC = _fxC,
				FxSeed = _fxSeed
			};
		}

		private static void OnFxRaised(char code, float a, float b, float c)
		{
			FxKind fxKind;
			switch (code)
			{
			default:
				return;
			case 'F':
				fxKind = FxKind.Flicker;
				break;
			case 'f':
				fxKind = FxKind.StopFlicker;
				break;
			case 'P':
				fxKind = FxKind.Pulse;
				break;
			case 'p':
				fxKind = FxKind.StopPulse;
				break;
			case 'B':
				fxKind = FxKind.Blink;
				break;
			}
			_fxSeq++;
			_fxKind = fxKind;
			_fxA = BeamWire.Q(a);
			_fxB = BeamWire.Q(b);
			_fxC = BeamWire.Q(c);
			_fxSeed = BeamWire.Q(FlashlightController.Instance.CurrentFxSeed);
		}

		private static int Byte(float v)
		{
			return Mathf.Clamp(Mathf.RoundToInt(v * 255f), 0, 255);
		}
	}
	internal enum FxKind
	{
		None,
		Flicker,
		StopFlicker,
		Pulse,
		StopPulse,
		Blink
	}
	internal struct BeamPost
	{
		public bool On;

		public int I100;

		public int R10;

		public int A10;

		public int Rgb24;

		public int FxSeq;

		public FxKind Fx;

		public int FxA;

		public int FxB;

		public int FxC;

		public int FxSeed;

		public float Intensity => (float)I100 / 100f;

		public float Range => (float)R10 / 10f;

		public float Angle => (float)A10 / 10f;

		public float R => (float)((Rgb24 >> 16) & 0xFF) / 255f;

		public float G => (float)((Rgb24 >> 8) & 0xFF) / 255f;

		public float B => (float)(Rgb24 & 0xFF) / 255f;

		public bool SameAs(BeamPost o)
		{
			if (On == o.On && I100 == o.I100 && R10 == o.R10 && A10 == o.A10 && Rgb24 == o.Rgb24)
			{
				return FxSeq == o.FxSeq;
			}
			return false;
		}
	}
	internal static class BeamWire
	{
		internal const string Prefix = "TB1|";

		internal const string Key = "doodesch_tightbeam";

		internal const int MaxPayloadChars = 128;

		private const int MinFields = 12;

		private const int MaxFields = 24;

		private static readonly CultureInfo Inv = CultureInfo.InvariantCulture;

		internal const int Endless = int.MaxValue;

		private const int MaxFinite = 60000;

		internal static string Encode(BeamPost p)
		{
			string[] obj = new string[22]
			{
				"TB1|",
				p.On ? "1" : "0",
				"|",
				p.I100.ToString(Inv),
				"|",
				p.R10.ToString(Inv),
				"|",
				p.A10.ToString(Inv),
				"|",
				(p.Rgb24 & 0xFFFFFF).ToString("X6", Inv),
				"|",
				p.FxSeq.ToString(Inv),
				"|",
				null,
				null,
				null,
				null,
				null,
				null,
				null,
				null,
				null
			};
			int fx = (int)p.Fx;
			obj[13] = fx.ToString(Inv);
			obj[14] = "|";
			obj[15] = p.FxA.ToString(Inv);
			obj[16] = "|";
			obj[17] = p.FxB.ToString(Inv);
			obj[18] = "|";
			obj[19] = p.FxC.ToString(Inv);
			obj[20] = "|";
			obj[21] = p.FxSeed.ToString(Inv);
			return string.Concat(obj);
		}

		internal static bool TryDecode(string raw, out BeamPost p)
		{
			p = default(BeamPost);
			if (raw == null || raw.Length > 128)
			{
				return false;
			}
			if (!raw.StartsWith("TB1|", StringComparison.Ordinal))
			{
				return false;
			}
			string[] array = raw.Split('|');
			if (array.Length < 12 || array.Length > 24)
			{
				return false;
			}
			if (!TryInt(array[1], out var v) || !TryInt(array[2], out p.I100) || !TryInt(array[3], out p.R10) || !TryInt(array[4], out p.A10))
			{
				return false;
			}
			if (!TryHex(array[5], out p.Rgb24))
			{
				return false;
			}
			if (!TryInt(array[6], out p.FxSeq) || !TryInt(array[7], out var v2) || !TryInt(array[8], out p.FxA) || !TryInt(array[9], out p.FxB) || !TryInt(array[10], out p.FxC) || !TryInt(array[11], out p.FxSeed))
			{
				return false;
			}
			if (v2 < 0 || v2 > 5)
			{
				return false;
			}
			p.On = v != 0;
			p.Fx = (FxKind)v2;
			p.I100 = Mathf.Clamp(p.I100, 0, 10000);
			p.R10 = Mathf.Clamp(p.R10, 20, 600);
			p.A10 = Mathf.Clamp(p.A10, 80, 900);
			p.Rgb24 &= 16777215;
			p.FxA = ClampFx(p.FxA);
			p.FxB = ClampFx(p.FxB);
			p.FxC = ClampFx(p.FxC);
			p.FxSeed = Mathf.Clamp(p.FxSeed, 0, 1000000);
			return true;
		}

		internal static int Q(float v)
		{
			if (float.IsNaN(v))
			{
				return 0;
			}
			if (float.IsPositiveInfinity(v))
			{
				return int.MaxValue;
			}
			double num = (double)v * 1000.0;
			if (num >= 2147483647.0)
			{
				return int.MaxValue;
			}
			if (num < 0.0)
			{
				return 0;
			}
			return (int)num;
		}

		internal static float Dq(int q)
		{
			if (q != int.MaxValue)
			{
				return (float)q / 1000f;
			}
			return float.PositiveInfinity;
		}

		private static int ClampFx(int q)
		{
			if (q != int.MaxValue)
			{
				return Mathf.Clamp(q, 0, 60000);
			}
			return int.MaxValue;
		}

		private static bool TryInt(string s, out int v)
		{
			return int.TryParse(s, NumberStyles.Integer, Inv, out v);
		}

		private static bool TryHex(string s, out int v)
		{
			v = 0;
			if (string.IsNullOrEmpty(s) || s.Length > 6)
			{
				return false;
			}
			for (int i = 0; i < s.Length; i++)
			{
				int num = HexDigit(s[i]);
				if (num < 0)
				{
					return false;
				}
				v = (v << 4) | num;
			}
			return true;
		}

		private static int HexDigit(char c)
		{
			if (c >= '0' && c <= '9')
			{
				return c - 48;
			}
			if (c >= 'A' && c <= 'F')
			{
				return c - 65 + 10;
			}
			if (c >= 'a' && c <= 'f')
			{
				return c - 97 + 10;
			}
			return -1;
		}
	}
	internal static class PlayerIdentity
	{
		internal static ulong SteamIdOf(Player p)
		{
			if ((Object)(object)p == (Object)null)
			{
				return 0uL;
			}
			try
			{
				string playerCode = p.PlayerCode;
				if (!string.IsNullOrEmpty(playerCode) && ulong.TryParse(playerCode, out var result))
				{
					return result;
				}
			}
			catch
			{
			}
			return 0uL;
		}

		internal static ulong LocalSteamId()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ulong steamID = SteamUser.GetSteamID().m_SteamID;
				if (steamID != 0L)
				{
					return steamID;
				}
			}
			catch
			{
			}
			try
			{
				return SteamIdOf(Player.Local);
			}
			catch
			{
				return 0uL;
			}
		}
	}
}
namespace TightBeam.Lighting
{
	internal struct BeamFx
	{
		private enum Mode
		{
			None,
			Flicker,
			Pulse
		}

		private Mode _mode;

		private float _strength;

		private float _freq;

		private float _amp;

		private float _period;

		private float _end;

		private float _seed;

		private int _blinkLeft;

		private float _blinkInterval;

		private float _blinkNext;

		private bool _blinkDark;

		public const int MaxBlinks = 20;

		public float Seed => _seed;

		public void Flicker(float strength01, float durationSeconds, float freqHz, float seed)
		{
			_mode = Mode.Flicker;
			_strength = Mathf.Clamp01(strength01);
			_freq = Mathf.Max(0.1f, freqHz);
			_end = Time.time + Mathf.Max(0.05f, durationSeconds);
			_seed = seed;
		}

		public void Pulse(float amp01, float periodSeconds, float durationSeconds, float seed)
		{
			_mode = Mode.Pulse;
			_amp = Mathf.Clamp01(amp01);
			_period = Mathf.Max(0.1f, periodSeconds);
			_end = (float.IsInfinity(durationSeconds) ? float.MaxValue : (Time.time + Mathf.Max(0.05f, durationSeconds)));
			_seed = seed;
		}

		public bool StopFlicker()
		{
			if (_mode != Mode.Flicker)
			{
				return false;
			}
			_mode = Mode.None;
			return true;
		}

		public bool StopPulse()
		{
			if (_mode != Mode.Pulse)
			{
				return false;
			}
			_mode = Mode.None;
			return true;
		}

		public void Blink(int times, float intervalSeconds)
		{
			if (times > 0)
			{
				_blinkLeft = Mathf.Min(times, 20) * 2;
				_blinkInterval = Mathf.Max(0.02f, intervalSeconds);
				_blinkNext = Time.time;
				_blinkDark = false;
			}
		}

		public void Clear()
		{
			_mode = Mode.None;
			_blinkLeft = 0;
			_blinkDark = false;
		}

		public float Multiplier()
		{
			float num = 1f;
			if (_mode == Mode.Flicker)
			{
				if (Time.time >= _end)
				{
					_mode = Mode.None;
				}
				else
				{
					float num2 = Mathf.PerlinNoise(Time.time * _freq + _seed, _seed * 0.37f);
					num *= Mathf.Lerp(1f - _strength, 1f, num2);
				}
			}
			else if (_mode == Mode.Pulse)
			{
				if (Time.time >= _end)
				{
					_mode = Mode.None;
				}
				else
				{
					num *= 1f + _amp * Mathf.Sin(Time.time * ((float)Math.PI * 2f / Mathf.Max(0.05f, _period)) + _seed);
				}
			}
			if (_blinkLeft > 0)
			{
				if (Time.time >= _blinkNext)
				{
					_blinkDark = !_blinkDark;
					_blinkLeft--;
					_blinkNext = Time.time + _blinkInterval;
				}
				if (_blinkDark)
				{
					num *= 0.04f;
				}
			}
			return Mathf.Max(0f, num);
		}
	}
	internal sealed class FlashlightController
	{
		private sealed class Ov
		{
			public int Token;

			public string Owner;

			public float? I;

			public float? R;

			public float? A;

			public Color? C;

			public float Expiry;
		}

		private GameObject _go;

		private Light _light;

		private Camera _cam;

		private bool _isOn;

		private float _focus;

		private float _focusTarget;

		private float _scrollVelEma;

		private float _intensity;

		private Color _color = Color.white;

		private float? _manualRange;

		private float? _manualAngle;

		private readonly List<Ov> _overrides = new List<Ov>();

		private int _nextToken = 1;

		private BeamFx _fx;

		private float _wireIntensity;

		private float _wireRange;

		private float _wireAngle;

		private Color _wireColor = Color.white;

		public static FlashlightController Instance { get; } = new FlashlightController();

		public bool IsOn => _isOn;

		public bool HasLight => (Object)(object)_light != (Object)null;

		public float WireIntensity => _wireIntensity;

		public float WireRange => _wireRange;

		public float WireSpotAngle => _wireAngle;

		public Color WireColor => _wireColor;

		public float Focus => _focus;

		public float CurrentIntensity
		{
			get
			{
				if (!((Object)(object)_light != (Object)null))
				{
					return 0f;
				}
				return _light.intensity;
			}
		}

		public float CurrentRange
		{
			get
			{
				if (!((Object)(object)_light != (Object)null))
				{
					return 0f;
				}
				return _light.range;
			}
		}

		public float CurrentSpotAngle
		{
			get
			{
				if (!((Object)(object)_light != (Object)null))
				{
					return 0f;
				}
				return _light.spotAngle;
			}
		}

		public Color CurrentColor
		{
			get
			{
				//IL_001a: 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)
				if (!((Object)(object)_light != (Object)null))
				{
					return Color.black;
				}
				return _light.color;
			}
		}

		public float CurrentFxSeed => _fx.Seed;

		public event Action<bool> Toggled;

		public event Action<char, float, float, float> FxRaised;

		public void InitFromPrefs()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			_focus = TightBeamPreferences.DefaultFocus;
			_focusTarget = _focus;
			_scrollVelEma = 0f;
			_intensity = TightBeamPreferences.DefaultIntensity;
			_color = TightBeamPreferences.Color;
		}

		public void EnsureRig()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			if ((Object)(object)_light == (Object)null)
			{
				_go = new GameObject("TightBeamLight");
				Object.DontDestroyOnLoad((Object)(object)_go);
				_light = _go.AddComponent<Light>();
				_light.type = (LightType)0;
				_light.renderMode = (LightRenderMode)0;
				_light.shadows = (LightShadows)(TightBeamPreferences.CastShadows ? 2 : 0);
				_light.shadowBias = 0.05f;
				_light.shadowNormalBias = 0.4f;
				((Behaviour)_light).enabled = false;
			}
			if ((Object)(object)_cam == (Object)null)
			{
				_cam = Camera.main;
			}
		}

		public void DisableRig()
		{
			if ((Object)(object)_light != (Object)null)
			{
				((Behaviour)_light).enabled = false;
			}
			VanillaLightSync.Restore();
		}

		public void Follow()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_light == (Object)null || !_isOn)
			{
				return;
			}
			if ((Object)(object)_cam == (Object)null)
			{
				_cam = Camera.main;
				if ((Object)(object)_cam == (Object)null)
				{
					return;
				}
			}
			Transform transform = ((Component)_cam).transform;
			_go.transform.position = transform.position + transform.forward * 0.25f + transform.right * 0.15f - transform.up * 0.2f;
			_go.transform.rotation = transform.rotation;
		}

		public void Tick(float dt)
		{
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: 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_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_light == (Object)null)
			{
				return;
			}
			if (!_isOn)
			{
				if (((Behaviour)_light).enabled)
				{
					((Behaviour)_light).enabled = false;
					VanillaLightSync.Apply(dark: false);
				}
				return;
			}
			float num = 1f - Mathf.Exp((0f - dt) / TightBeamPreferences.FocusEaseTau);
			_focus = Mathf.Lerp(_focus, _focusTarget, num);
			if (Mathf.Abs(_focusTarget - _focus) < 0.0005f)
			{
				_focus = _focusTarget;
			}
			float num2 = _manualRange ?? Mathf.Lerp(TightBeamPreferences.RangeNarrow, TightBeamPreferences.RangeWide, _focus);
			float num3 = _manualAngle ?? Mathf.Lerp(TightBeamPreferences.AngleNarrow, TightBeamPreferences.AngleWide, _focus);
			float intensity = _intensity;
			Color color = _color;
			PruneOverrides();
			float num4 = num2;
			float num5 = num3;
			float num6 = intensity;
			Color val = color;
			for (int num7 = _overrides.Count - 1; num7 >= 0; num7--)
			{
				Ov ov = _overrides[num7];
				if (ov.I.HasValue && num6 == intensity)
				{
					num6 = ov.I.Value;
				}
				if (ov.R.HasValue && num4 == num2)
				{
					num4 = ov.R.Value;
				}
				if (ov.A.HasValue && num5 == num3)
				{
					num5 = ov.A.Value;
				}
				if (ov.C.HasValue && val == color)
				{
					val = ov.C.Value;
				}
			}
			_wireIntensity = num6;
			_wireRange = num4;
			_wireAngle = num5;
			_wireColor = val;
			num6 *= _fx.Multiplier();
			_light.intensity = Mathf.Max(0f, num6);
			_light.range = Mathf.Clamp(num4, 2f, 60f);
			_light.spotAngle = Mathf.Clamp(num5, 8f, 90f);
			_light.innerSpotAngle = _light.spotAngle * 0.6f;
			_light.color = val;
			((Behaviour)_light).enabled = _isOn;
			VanillaLightSync.Apply(_isOn);
		}

		private void PruneOverrides()
		{
			for (int num = _overrides.Count - 1; num >= 0; num--)
			{
				if (_overrides[num].Expiry > 0f && Time.time > _overrides[num].Expiry)
				{
					_overrides.RemoveAt(num);
				}
			}
		}

		public void SyncOnFromGame()
		{
			bool flag = false;
			try
			{
				if (PlayerSingleton<Phone>.InstanceExists)
				{
					GameObject phoneFlashlight = PlayerSingleton<Phone>.Instance.PhoneFlashlight;
					flag = (Object)(object)phoneFlashlight != (Object)null && phoneFlashlight.activeSelf;
				}
			}
			catch
			{
				return;
			}
			if (flag != _isOn)
			{
				_isOn = flag;
				try
				{
					this.Toggled?.Invoke(flag);
				}
				catch
				{
				}
			}
		}

		public void SetOn(bool on)
		{
			try
			{
				if (PlayerSingleton<Phone>.InstanceExists && PlayerSingleton<Phone>.Instance.FlashlightOn != on)
				{
					PlayerSingleton<Phone>.Instance.ToggleFlashlight();
				}
			}
			catch
			{
			}
		}

		public void Toggle()
		{
			try
			{
				if (PlayerSingleton<Phone>.InstanceExists)
				{
					PlayerSingleton<Phone>.Instance.ToggleFlashlight();
				}
			}
			catch
			{
			}
		}

		private void MoveFocusTarget(float delta)
		{
			_focusTarget = Mathf.Clamp01(_focusTarget + delta);
			_manualRange = null;
			_manualAngle = null;
		}

		private void SnapFocusTarget(float value)
		{
			_focusTarget = Mathf.Clamp01(value);
			_manualRange = null;
			_manualAngle = null;
		}

		public void NudgeFocus(float delta)
		{
			MoveFocusTarget(delta);
		}

		public void UpdateFocusScroll(float scrollDelta, float dt)
		{
			if (Mathf.Abs(scrollDelta) > 0.0001f)
			{
				float num = Mathf.Abs(scrollDelta) / Mathf.Max(dt, 0.004166667f);
				float num2 = 1f - Mathf.Exp((0f - dt) / TightBeamPreferences.FocusVelAttackTau);
				_scrollVelEma = Mathf.Lerp(_scrollVelEma, num, num2);
				float focusVelocityRefRate = TightBeamPreferences.FocusVelocityRefRate;
				float num3 = focusVelocityRefRate * TightBeamPreferences.FocusFlickRateMultiplier;
				float num4 = (TightBeamPreferences.InvertFocusScroll ? (-1f) : 1f);
				float num5 = Mathf.Sign(scrollDelta) * num4;
				if (_scrollVelEma >= num3)
				{
					SnapFocusTarget((num5 > 0f) ? 1f : 0f);
					return;
				}
				float num6 = Mathf.Clamp01((_scrollVelEma - focusVelocityRefRate) / Mathf.Max(0.0001f, num3 - focusVelocityRefRate));
				float num7 = Mathf.Lerp(TightBeamPreferences.FocusSensitivity, TightBeamPreferences.FocusMaxStep, Mathf.Pow(num6, TightBeamPreferences.FocusVelocityGamma));
				MoveFocusTarget(num5 * num7);
			}
			else
			{
				float num8 = 1f - Mathf.Exp((0f - dt) / TightBeamPreferences.FocusVelDecayTau);
				_scrollVelEma = Mathf.Lerp(_scrollVelEma, 0f, num8);
			}
		}

		public void ResetFocusScrollVelocity()
		{
			_scrollVelEma = 0f;
		}

		public void SetIntensity(float v)
		{
			_intensity = Mathf.Clamp(v, TightBeamPreferences.MinIntensity, TightBeamPreferences.MaxIntensity);
		}

		public void SetColor(Color c)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			_color = c;
		}

		public void SetBaseRange(float v)
		{
			_manualRange = Mathf.Clamp(v, 2f, 60f);
		}

		public void SetBaseSpotAngle(float v)
		{
			_manualAngle = Mathf.Clamp(v, 8f, 90f);
		}

		public int BeginOverride(string owner)
		{
			Ov ov = new Ov
			{
				Token = _nextToken++,
				Owner = owner
			};
			_overrides.Add(ov);
			return ov.Token;
		}

		public void EndOverride(int token)
		{
			for (int i = 0; i < _overrides.Count; i++)
			{
				if (_overrides[i].Token == token)
				{
					_overrides.RemoveAt(i);
					break;
				}
			}
		}

		private Ov Find(int token)
		{
			for (int i = 0; i < _overrides.Count; i++)
			{
				if (_overrides[i].Token == token)
				{
					return _overrides[i];
				}
			}
			return null;
		}

		public void OverrideIntensity(int token, float v)
		{
			Ov ov = Find(token);
			if (ov != null)
			{
				ov.I = v;
			}
		}

		public void OverrideRange(int token, float v)
		{
			Ov ov = Find(token);
			if (ov != null)
			{
				ov.R = v;
			}
		}

		public void OverrideSpotAngle(int token, float v)
		{
			Ov ov = Find(token);
			if (ov != null)
			{
				ov.A = v;
			}
		}

		public void OverrideColor(int token, Color c)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Ov ov = Find(token);
			if (ov != null)
			{
				ov.C = c;
			}
		}

		public void ClearOverrideIntensity(int token)
		{
			Ov ov = Find(token);
			if (ov != null)
			{
				ov.I = null;
			}
		}

		public void ClearOverrideRange(int token)
		{
			Ov ov = Find(token);
			if (ov != null)
			{
				ov.R = null;
			}
		}

		public void ClearOverrideSpotAngle(int token)
		{
			Ov ov = Find(token);
			if (ov != null)
			{
				ov.A = null;
			}
		}

		public void ClearOverrideColor(int token)
		{
			Ov ov = Find(token);
			if (ov != null)
			{
				ov.C = null;
			}
		}

		public void TemporaryIntensity(float v, float seconds)
		{
			_overrides.Add(new Ov
			{
				Token = _nextToken++,
				Owner = "$temp",
				I = v,
				Expiry = Time.time + Mathf.Max(0.05f, seconds)
			});
		}

		public void TemporaryColor(float r, float g, float b, float a, float seconds)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			_overrides.Add(new Ov
			{
				Token = _nextToken++,
				Owner = "$temp",
				C = new Color(r, g, b, a),
				Expiry = Time.time + Mathf.Max(0.05f, seconds)
			});
		}

		public void Flicker(float strength01, float durationSeconds, float freqHz)
		{
			_fx.Flicker(strength01, durationSeconds, freqHz, Random.value * 100f);
			RaiseFx('F', Mathf.Clamp01(strength01), durationSeconds, Mathf.Max(0.1f, freqHz));
		}

		public void Pulse(float amp01, float periodSeconds, float durationSeconds)
		{
			_fx.Pulse(amp01, periodSeconds, durationSeconds, Random.value * 6.28f);
			RaiseFx('P', Mathf.Clamp01(amp01), Mathf.Max(0.1f, periodSeconds), durationSeconds);
		}

		public void StopFlicker()
		{
			if (_fx.StopFlicker())
			{
				RaiseFx('f', 0f, 0f, 0f);
			}
		}

		public void StopPulse()
		{
			if (_fx.StopPulse())
			{
				RaiseFx('p', 0f, 0f, 0f);
			}
		}

		public void Blink(int times, float intervalSeconds)
		{
			if (_isOn && times > 0)
			{
				_fx.Blink(times, intervalSeconds);
				RaiseFx('B', times, Mathf.Max(0.02f, intervalSeconds), 0f);
			}
		}

		private void RaiseFx(char code, float a, float b, float c)
		{
			try
			{
				this.FxRaised?.Invoke(code, a, b, c);
			}
			catch
			{
			}
		}
	}
	internal static class RemoteBeams
	{
		private sealed class Entry
		{
			public Player Owner;

			public ulong SteamId;

			public Transform Anchor;

			public bool Lit;

			public bool ToggleOwed;

			public Vector3 Pos;

			public Quaternion Rot;

			public bool PoseInit;

			public float Intensity;

			public float Range;

			public float Angle;

			public Color Color;

			public bool ParamsInit;

			public bool HasPost;

			public BeamPost Post;

			public BeamFx Fx;

			public float FxMul = 1f;

			public int LastFxSeq;

			public bool LastVanillaActive;

			public bool SawVanillaTransition;

			public OptimizedLight SupThird;

			public OptimizedLight SupEquip;

			public bool SupThirdTaken;

			public bool SupEquipTaken;

			public int Rig = -1;

			public bool Selected;

			public float Dist2;
		}

		private const float RosterInterval = 0.2f;

		private const float SelectInterval = 0.1f;

		private static readonly Vector3 HandOffset = new Vector3(0.15f, -0.2f, 0.25f);

		private static readonly Dictionary<ulong, Entry> _byId = new Dictionary<ulong, Entry>();

		private static readonly List<Entry> _entries = new List<Entry>();

		private static readonly List<Entry> _pending = new List<Entry>();

		private static readonly Il2CppStructArray<Plane> _frustum = new Il2CppStructArray<Plane>(6L);

		private static GameObject[] _rigGo;

		private static Light[] _rigLight;

		private static Entry[] _winners;

		private static int _winnerCount;

		private static float _nextRoster;

		private static float _nextSelect;

		private static bool _broken;

		private static readonly List<Action<ulong, bool>> _toggledListeners = new List<Action<ulong, bool>>();

		private static readonly ulong[] _noIds = new ulong[0];

		internal static int ActiveCount { get; private set; }

		internal static int CandidateCount { get; private set; }

		internal static int TrackedCount => _entries.Count;

		public static void Tick(float dt)
		{
			if (_broken)
			{
				return;
			}
			try
			{
				TickInner(dt);
			}
			catch (Exception ex)
			{
				_broken = true;
				Instance log = Core.Log;
				if (log != null)
				{
					log.Error("RemoteBeams disabled for this session after an error: " + ex);
				}
				try
				{
					DisableAll();
				}
				catch
				{
				}
			}
		}

		private static void TickInner(float dt)
		{
			int maxRemoteBeams = TightBeamPreferences.MaxRemoteBeams;
			bool num = TightBeamPreferences.RemoteBeams && maxRemoteBeams > 0;
			if (Time.time >= _nextRoster)
			{
				_nextRoster = Time.time + 0.2f;
				RefreshRoster();
			}
			bool flag = Time.time >= _nextSelect;
			if (flag)
			{
				_nextSelect = Time.time + 0.1f;
			}
			if (!num)
			{
				if (flag)
				{
					Evaluate();
				}
				ReleaseAll();
				CandidateCount = 0;
				return;
			}
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				if (flag)
				{
					Evaluate();
				}
				ReleaseAll();
				return;
			}
			if (_entries.Count == 0)
			{
				ReleaseAll();
				CandidateCount = 0;
				return;
			}
			EnsurePool(maxRemoteBeams);
			if (flag)
			{
				Evaluate();
				Select(main, maxRemoteBeams);
			}
			int remoteShadowNearest = TightBeamPreferences.RemoteShadowNearest;
			for (int i = 0; i < _winnerCount; i++)
			{
				Entry entry = _winners[i];
				if (entry != null && entry.Selected)
				{
					entry.FxMul = entry.Fx.Multiplier();
					if (!ResolveAnchor(entry))
					{
						Release(entry);
					}
					else
					{
						Render(entry, i, i < remoteShadowNearest, dt);
					}
				}
			}
			ActiveCount = _winnerCount;
		}

		private static void Evaluate()
		{
			for (int i = 0; i < _entries.Count; i++)
			{
				Entry entry = _entries[i];
				PullPost(entry);
				bool flag = IsLit(entry);
				if (flag != entry.Lit)
				{
					entry.Lit = flag;
					RaiseToggled(entry);
				}
			}
		}

		private static void Select(Camera cam, int cap)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			GeometryUtility.CalculateFrustumPlanes(cam, _frustum);
			Vector3 position = ((Component)cam).transform.position;
			float remoteBeamMaxDistance = TightBeamPreferences.RemoteBeamMaxDistance;
			float num = remoteBeamMaxDistance * remoteBeamMaxDistance;
			int num2 = 0;
			int num3 = 0;
			for (int i = 0; i < _entries.Count; i++)
			{
				Entry entry = _entries[i];
				entry.Selected = false;
				if (!entry.Lit)
				{
					Release(entry);
					continue;
				}
				if (!entry.HasPost && !TightBeamPreferences.RemoteBeamsForUnmoddedPlayers)
				{
					Release(entry);
					continue;
				}
				if (!ResolveAnchor(entry))
				{
					Release(entry);
					continue;
				}
				Vector3 position2 = entry.Anchor.position;
				Vector3 val = position2 - position;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (sqrMagnitude > num)
				{
					Release(entry);
					continue;
				}
				float range = entry.Range;
				if (!entry.ParamsInit)
				{
					TargetParams(entry, out var _, out range, out var _, out var _);
				}
				if (!ConeVisible(position2, entry.Anchor.forward, range))
				{
					Release(entry);
					continue;
				}
				num2++;
				entry.Dist2 = sqrMagnitude;
				if (num3 < cap)
				{
					_winners[num3++] = entry;
					continue;
				}
				int num4 = 0;
				for (int j = 1; j < cap; j++)
				{
					if (_winners[j].Dist2 > _winners[num4].Dist2)
					{
						num4 = j;
					}
				}
				if (_winners[num4].Dist2 <= sqrMagnitude)
				{
					Release(entry);
					continue;
				}
				Release(_winners[num4]);
				_winners[num4] = entry;
			}
			CandidateCount = num2;
			SortWinners(num3);
			for (int k = 0; k < num3; k++)
			{
				_winners[k].Selected = true;
			}
			for (int l = num3; l < _rigGo.Length; l++)
			{
				SetRigActive(l, on: false);
			}
			_winnerCount = num3;
		}

		private static void RefreshRoster()
		{
			try
			{
				List<Player> playerList = Player.PlayerList;
				if (playerList == null)
				{
					return;
				}
				for (int num = _entries.Count - 1; num >= 0; num--)
				{
					Entry entry = _entries[num];
					if (!((Object)(object)entry.Owner != (Object)null))
					{
						Forget(entry, num);
					}
				}
				for (int i = 0; i < playerList.Count; i++)
				{
					Player val = playerList[i];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					bool isLocalPlayer;
					try
					{
						isLocalPlayer = val.IsLocalPlayer;
					}
					catch
					{
						continue;
					}
					if (isLocalPlayer)
					{
						continue;
					}
					ulong num2 = PlayerIdentity.SteamIdOf(val);
					Entry entry2 = ((num2 != 0L && _byId.TryGetValue(num2, out var value)) ? value : FindPending(val));
					if (entry2 == null)
					{
						entry2 = new Entry
						{
							Owner = val,
							SteamId = num2
						};
						_entries.Add(entry2);
						if (num2 != 0L)
						{
							_byId[num2] = entry2;
						}
						else
						{
							_pending.Add(entry2);
						}
						continue;
					}
					entry2.Owner = val;
					if (entry2.SteamId == 0L && num2 != 0L)
					{
						entry2.SteamId = num2;
						_byId[num2] = entry2;
						_pending.Remove(entry2);
						if (entry2.ToggleOwed)
						{
							RaiseToggled(entry2);
						}
					}
				}
				for (int num3 = _entries.Count - 1; num3 >= 0; num3--)
				{
					Entry entry3 = _entries[num3];
					bool flag = false;
					for (int j = 0; j < playerList.Count; j++)
					{
						if (playerList[j] == entry3.Owner)
						{
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						Forget(entry3, num3);
					}
				}
			}
			catch (Exception ex)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("RemoteBeams roster failed: " + ex.Message);
				}
			}
		}

		private static Entry FindPending(Player p)
		{
			for (int i = 0; i < _pending.Count; i++)
			{
				if (_pending[i].Owner == p)
				{
					return _pending[i];
				}
			}
			return null;
		}

		private static void Forget(Entry e, int index)
		{
			Release(e);
			_entries.RemoveAt(index);
			_pending.Remove(e);
			if (e.SteamId != 0L)
			{
				_byId.Remove(e.SteamId);
			}
		}

		private static void PullPost(Entry e)
		{
			if (e.SteamId == 0L)
			{
				return;
			}
			bool hasPost = e.HasPost;
			e.HasPost = BeamBoard.TryGet(e.SteamId, out var post);
			if (!e.HasPost)
			{
				if (hasPost)
				{
					e.Fx.Clear();
				}
				return;
			}
			e.Post = post;
			if (!hasPost)
			{
				e.LastFxSeq = post.FxSeq;
			}
			else if (post.FxSeq != e.LastFxSeq)
			{
				e.LastFxSeq = post.FxSeq;
				ApplyFx(e, post);
			}
		}

		private static void ApplyFx(Entry e, BeamPost p)
		{
			float num = BeamWire.Dq(p.FxA);
			float num2 = BeamWire.Dq(p.FxB);
			float num3 = BeamWire.Dq(p.FxC);
			float seed = (float)p.FxSeed / 1000f;
			switch (p.Fx)
			{
			case FxKind.Flicker:
				e.Fx.Flicker(num, num2, num3, seed);
				break;
			case FxKind.StopFlicker:
				e.Fx.StopFlicker();
				break;
			case FxKind.Pulse:
				e.Fx.Pulse(num, num2, num3, seed);
				break;
			case FxKind.StopPulse:
				e.Fx.StopPulse();
				break;
			case FxKind.Blink:
				e.Fx.Blink(Mathf.RoundToInt(num), num2);
				break;
			}
		}

		private static bool IsLit(Entry e)
		{
			try
			{
				if ((Object)(object)e.Owner == (Object)null)
				{
					return false;
				}
				OptimizedLight thirdPersonFlashlight = e.Owner.ThirdPersonFlashlight;
				bool flag = (Object)(object)thirdPersonFlashlight != (Object)null && ((Component)thirdPersonFlashlight).gameObject.activeSelf;
				if (flag != e.LastVanillaActive)
				{
					e.LastVanillaActive = flag;
					e.SawVanillaTransition = true;
				}
				return ((e.SawVanillaTransition || !e.HasPost) ? flag : e.Post.On) && !e.Owner.IsInVehicle;
			}
			catch
			{
				return false;
			}
		}

		private static bool ResolveAnchor(Entry e)
		{
			try
			{
				if ((Object)(object)e.Owner == (Object)null)
				{
					return false;
				}
				Transform val = e.Owner.MimicCamera;
				if ((Object)(object)val == (Object)null)
				{
					Avatar avatar = e.Owner.Avatar;
					if ((Object)(object)avatar != (Object)null && (Object)(object)avatar.Eyes != (Object)null)
					{
						val = ((Component)avatar.Eyes).transform;
					}
					if ((Object)(object)val == (Object)null && (Object)(object)e.Owner.ThirdPersonFlashlight != (Object)null)
					{
						val = ((Component)e.Owner.ThirdPersonFlashlight).transform;
					}
					if ((Object)(object)val == (Object)null)
					{
						val = ((Component)e.Owner).transform;
					}
				}
				e.Anchor = val;
				return (Object)(object)val != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		internal static void AddToggledListener(Action<ulong, bool> cb)
		{
			if (cb != null)
			{
				_toggledListeners.Add(cb);
			}
		}

		private static void RaiseToggled(Entry e)
		{
			if (e.SteamId == 0L)
			{
				e.ToggleOwed = true;
				return;
			}
			e.ToggleOwed = false;
			for (int i = 0; i < _toggledListeners.Count; i++)
			{
				try
				{
					_toggledListeners[i](e.SteamId, e.Lit);
				}
				catch
				{
				}
			}
		}

		internal static bool InMultiplayer()
		{
			try
			{
				List<Player> playerList = Player.PlayerList;
				return playerList != null && playerList.Count > 1;
			}
			catch
			{
				return false;
			}
		}

		internal static ulong[] RemoteIds()
		{
			ulong[] array = BeamBoard.PostedIds();
			if (_byId.Count == 0)
			{
				return array;
			}
			List<ulong> list = new List<ulong>(array);
			foreach (ulong key in _byId.Keys)
			{
				if (!list.Contains(key))
				{
					list.Add(key);
				}
			}
			if (list.Count != 0)
			{
				return list.ToArray();
			}
			return _noIds;
		}

		internal static bool HasSyncedBeam(ulong steamId)
		{
			BeamPost post;
			return BeamBoard.TryGet(steamId, out post);
		}

		internal static float[] BeamOf(ulong steamId)
		{
			//IL_0031: 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_0085: 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_0099: 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)
			if (_byId.TryGetValue(steamId, out var value))
			{
				float intensity;
				float range;
				float angle;
				Color color;
				if (value.ParamsInit)
				{
					intensity = value.Intensity;
					range = value.Range;
					angle = value.Angle;
					color = value.Color;
				}
				else
				{
					TargetParams(value, out intensity, out range, out angle, out color);
				}
				return new float[8]
				{
					value.Lit ? 1f : 0f,
					Mathf.Max(0f, intensity * value.FxMul),
					range,
					angle,
					color.r,
					color.g,
					color.b,
					color.a
				};
			}
			if (!BeamBoard.TryGet(steamId, out var post))
			{
				return null;
			}
			return new float[8]
			{
				post.On ? 1f : 0f,
				Mathf.Min(post.Intensity, TightBeamPreferences.MaxIntensity),
				post.Range,
				post.Angle,
				post.R,
				post.G,
				post.B,
				1f
			};
		}

		internal static float[] PoseOf(ulong steamId)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (!_byId.TryGetValue(steamId, out var value) || !value.PoseInit)
			{
				return null;
			}
			Vector3 val = value.Pos + value.Rot * HandOffset;
			Vector3 val2 = value.Rot * Vector3.forward;
			return new float[6] { val.x, val.y, val.z, val2.x, val2.y, val2.z };
		}

		internal static bool IsRendered(ulong steamId)
		{
			if (_byId.TryGetValue(steamId, out var value))
			{
				return value.Rig >= 0;
			}
			return false;
		}

		private static void Render(Entry e, int slot, bool shadows, float dt)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_006e: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			e.Rig = slot;
			Vector3 position = e.Anchor.position;
			Quaternion rotation = e.Anchor.rotation;
			if (!e.PoseInit)
			{
				e.Pos = position;
				e.Rot = rotation;
				e.PoseInit = true;
			}
			else
			{
				float num = 1f - Mathf.Exp((0f - dt) / TightBeamPreferences.RemoteSmoothingTau);
				e.Pos = Vector3.Lerp(e.Pos, position, num);
				e.Rot = Quaternion.Slerp(e.Rot, rotation, num);
			}
			ResolveParams(e, dt);
			GameObject val = _rigGo[slot];
			Light obj = _rigLight[slot];
			val.transform.position = e.Pos + e.Rot * HandOffset;
			val.transform.rotation = e.Rot;
			obj.intensity = Mathf.Max(0f, e.Intensity * e.FxMul);
			obj.range = Mathf.Clamp(e.Range, 2f, 60f);
			obj.spotAngle = Mathf.Clamp(e.Angle, 8f, 90f);
			obj.innerSpotAngle = obj.spotAngle * 0.6f;
			obj.color = e.Color;
			obj.shadows = (LightShadows)(shadows ? 2 : 0);
			if (!val.activeSelf)
			{
				val.SetActive(true);
			}
			((Behaviour)obj).enabled = true;
			Suppress(e);
		}

		private static void TargetParams(Entry e, out float intensity, out float range, out float angle, out Color color)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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)
			if (e.HasPost)
			{
				intensity = Mathf.Min(e.Post.Intensity, TightBeamPreferences.MaxIntensity);
				range = e.Post.Range;
				angle = e.Post.Angle;
				color = new Color(e.Post.R, e.Post.G, e.Post.B, 1f);
			}
			else
			{
				float defaultFocus = TightBeamPreferences.DefaultFocus;
				intensity = TightBeamPreferences.DefaultIntensity;
				range = Mathf.Lerp(TightBeamPreferences.RangeNarrow, TightBeamPreferences.RangeWide, defaultFocus);
				angle = Mathf.Lerp(TightBeamPreferences.AngleNarrow, TightBeamPreferences.AngleWide, defaultFocus);
				color = TightBeamPreferences.Color;
			}
		}

		private static void ResolveParams(Entry e, float dt)
		{
			//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)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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)
			TargetParams(e, out var intensity, out var range, out var angle, out var color);
			if (!e.ParamsInit)
			{
				e.Intensity = intensity;
				e.Range = range;
				e.Angle = angle;
				e.Color = color;
				e.ParamsInit = true;
			}
			else
			{
				float num = 1f - Mathf.Exp((0f - dt) / TightBeamPreferences.FocusEaseTau);
				e.Intensity = Mathf.Lerp(e.Intensity, intensity, num);
				e.Range = Mathf.Lerp(e.Range, range, num);
				e.Angle = Mathf.Lerp(e.Angle, angle, num);
				e.Color = Color.Lerp(e.Color, color, num);
			}
		}

		private static bool ConeVisible(Vector3 origin, Vector3 forward, float range)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0013: 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_002b: 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)
			Vector3 val = origin + forward * (range * 0.5f);
			float num = range * 0.55f;
			for (int i = 0; i < 6; i++)
			{
				Plane val2 = ((Il2CppArrayBase<Plane>)(object)_frustum)[i];
				if (((Plane)(ref val2)).GetDistanceToPoint(val) < 0f - num)
				{
					return false;
				}
			}
			return true;
		}

		private static void SortWinners(int count)
		{
			for (int i = 1; i < count; i++)
			{
				Entry entry = _winners[i];
				int num = i - 1;
				while (num >= 0 && _winners[num].Dist2 > entry.Dist2)
				{
					_winners[num + 1] = _winners[num];
					num--;
				}
				_winners[num + 1] = entry;
			}
		}

		private static void EnsurePool(int cap)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			if (_rigGo != null && _rigGo.Length >= cap)
			{
				if (_winners == null || _winners.Length < cap)
				{
					_winners = new Entry[cap];
				}
				return;
			}
			GameObject[] array = (GameObject[])(object)new GameObject[cap];
			Light[] array2 = (Light[])(object)new Light[cap];
			int num = ((_rigGo != null) ? _rigGo.Length : 0);
			for (int i = 0; i < num; i++)
			{
				array[i] = _rigGo[i];
				array2[i] = _rigLight[i];
			}
			for (int j = num; j < cap; j++)
			{
				array[j] = new GameObject("TightBeamRemote" + j);
				Object.DontDestroyOnLoad((Object)(object)array[j]);
				array2[j] = array[j].AddComponent<Light>();
				array2[j].type = (LightType)0;
				array2[j].renderMode = (LightRenderMode)0;
				array2[j].shadows = (LightShadows)0;
				array2[j].shadowBias = 0.05f;
				array2[j].shadowNormalBias = 0.4f;
				((Behaviour)array2[j]).enabled = false;
				array[j].SetActive(false);
			}
			_rigGo = array;
			_rigLight = array2;
			_winners = new Entry[cap];
		}

		private static void SetRigActive(int slot, bool on)
		{
			if (_rigGo != null && slot >= 0 && slot < _rigGo.Length && !((Object)(object)_rigGo[slot] == (Object)null))
			{
				if ((Object)(object)_rigLight[slot] != (Object)null)
				{
					((Behaviour)_rigLight[slot]).enabled = on;
				}
				if (_rigGo[slot].activeSelf != on)
				{
					_rigGo[slot].SetActive(on);
				}
			}
		}

		private static void Suppress(Entry e)
		{
			if (!TightBeamPreferences.SuppressRemoteVanillaLights)
			{
				Restore(e);
				return;
			}
			try
			{
				OptimizedLight val = (((Object)(object)e.Owner != (Object)null) ? e.Owner.ThirdPersonFlashlight : null);
				if (val != e.SupThird)
				{
					Give(e.SupThird, e.SupThirdTaken);
					e.SupThird = val;
					e.SupThirdTaken = false;
				}
				if (Take(e.SupThird))
				{
					e.SupThirdTaken = true;
				}
				OptimizedLight val2 = null;
				Avatar val3 = (((Object)(object)e.Owner != (Object)null) ? e.Owner.Avatar : null);
				if ((Object)(object)val3 != (Object)null)
				{
					AvatarEquippable currentEquippable = val3.CurrentEquippable;
					if ((Object)(object)currentEquippable != (Object)null)
					{
						FlashlightAvatarEquippable val4 = ((Il2CppObjectBase)currentEquippable).TryCast<FlashlightAvatarEquippable>();
						if ((Object)(object)val4 != (Object)null)
						{
							val2 = val4.Light;
						}
					}
				}
				if (val2 != e.SupEquip)
				{
					Give(e.SupEquip, e.SupEquipTaken);
					e.SupEquip = val2;
					e.SupEquipTaken = false;
				}
				if (Take(e.SupEquip))
				{
					e.SupEquipTaken = true;
				}
			}
			catch (Exception ex)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("RemoteBeams suppress failed: " + ex.Message);
				}
			}
		}

		private static void Restore(Entry e)
		{
			Give(e.SupThird, e.SupThirdTaken);
			e.SupThird = null;
			e.SupThirdTaken = false;
			Give(e.SupEquip, e.SupEquipTaken);
			e.SupEquip = null;
			e.SupEquipTaken = false;
		}

		private static bool Take(OptimizedLight ol)
		{
			try
			{
				if ((Object)(object)ol != (Object)null && ol.Enabled)
				{
					ol.Enabled = false;
					ol.UpdateLightState();
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static void Give(OptimizedLight ol, bool weTurnedItOff)
		{
			if (!weTurnedItOff)
			{
				return;
			}
			try
			{
				if ((Object)(object)ol != (Object)null && !ol.Enabled)
				{
					ol.Enabled = true;
					ol.UpdateLightState();
				}
			}
			catch
			{
			}
		}

		public static void NewSession()
		{
			_broken = false;
			try
			{
				DisableAll();
			}
			catch
			{
			}
			_nextRoster = 0f;
			_nextSelect = 0f;
		}

		public static void DisableAll()
		{
			ReleaseAll();
			_entries.Clear();
			_byId.Clear();
			_pending.Clear();
			ActiveCount = 0;
			CandidateCount = 0;
		}

		private static void Release(Entry e)
		{
			e.Rig = -1;
			e.Selected = false;
			Restore(e);
			e.PoseInit = false;
			e.ParamsInit = false;
		}

		private static void ReleaseAll()
		{
			for (int i = 0; i < _entries.Count; i++)
			{
				Release(_entries[i]);
			}
			if (_rigGo != null)
			{
				for (int j = 0; j < _rigGo.Length; j++)
				{
					SetRigActive(j, on: false);
				}
			}
			_winnerCount = 0;
			ActiveCount = 0;
		}
	}
	internal static class VanillaLightSync
	{
		private static readonly List<OptimizedLight> _opt = new List<OptimizedLight>();

		private static readonly List<Light> _bare = new List<Light>();

		private static bool _dark;

		private static float _nextRescan;

		public static void Apply(bool dark)
		{
			if (dark)
			{
				if (!_dark)
				{
					_dark = true;
					_nextRescan = 0f;
				}
				ReassertDisabled();
				if (Time.time >= _nextRescan)
				{
					_nextRescan = Time.time + 0.1f;
					Capture();
				}
			}
			else if (_dark)
			{
				Restore();
			}
		}

		private static void ReassertDisabled()
		{
			for (int i = 0; i < _opt.Count; i++)
			{
				OptimizedLight val = _opt[i];
				if ((Object)(object)val != (Object)null && val.Enabled)
				{
					val.Enabled = false;
					val.UpdateLightState();
				}
			}
			for (int j = 0; j < _bare.Count; j++)
			{
				Light val2 = _bare[j];
				if ((Object)(object)val2 != (Object)null && ((Behaviour)val2).enabled)
				{
					((Behaviour)val2).enabled = false;
				}
			}
		}

		private static void Capture()
		{
			try
			{
				if (PlayerSingleton<PlayerInventory>.InstanceExists)
				{
					Equippable equippable = PlayerSingleton<PlayerInventory>.Instance.Equippable;
					if ((Object)(object)equippable != (Object)null && (Object)(object)((Il2CppObjectBase)equippable).TryCast<Flashlight>() != (Object)null)
					{
						DisableUnder(((Component)equippable).gameObject);
					}
				}
				if (PlayerSingleton<Phone>.InstanceExists)
				{
					GameObject phoneFlashlight = PlayerSingleton<Phone>.Instance.PhoneFlashlight;
					if ((Object)(object)phoneFlashlight != (Object)null)
					{
						DisableUnder(phoneFlashlight);
					}
				}
			}
			catch (Exception ex)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("VanillaLightSync capture failed: " + ex.Message);
				}
			}
		}

		private static void DisableUnder(GameObject root)
		{
			foreach (OptimizedLight componentsInChild in root.GetComponentsInChildren<OptimizedLight>(true))
			{
				if (!((Object)(object)componentsInChild == (Object)null) && componentsInChild.Enabled)
				{
					componentsInChild.Enabled = false;
					componentsInChild.UpdateLightState();
					_opt.Add(componentsInChild);
				}
			}
			foreach (Light componentsInChild2 in root.GetComponentsInChildren<Light>(true))
			{
				if (!((Object)(object)componentsInChild2 == (Object)null) && ((Behaviour)componentsInChild2).enabled && !((Object)(object)((Component)componentsInChild2).GetComponent<OptimizedLight>() != (Object)null))
				{
					((Behaviour)componentsInChild2).enabled = false;
					_bare.Add(componentsInChild2);
				}
			}
		}

		public static void Restore()
		{
			_dark = false;
			foreach (OptimizedLight item in _opt)
			{
				try
				{
					if ((Object)(object)item != (Object)null)
					{
						item.Enabled = true;
						item.UpdateLightState();
					}
				}
				catch
				{
				}
			}
			foreach (Light item2 in _bare)
			{
				try
				{
					if ((Object)(object)item2 != (Object)null)
					{
						((Behaviour)item2).enabled = true;
					}
				}
				catch
				{
				}
			}
			_opt.Clear();
			_bare.Clear();
		}
	}
}
namespace TightBeam.Config
{
	internal static class TightBeamPreferences
	{
		private static MelonPreferences_Category _cat;

		private static MelonPreferences_Entry<bool> _enabled;

		private static MelonPreferences_Entry<string> _focusModifierKey;

		private static MelonPreferences_Entry<float> _defaultIntensity;

		private static MelonPreferences_Entry<float> _minIntensity;

		private static MelonPreferences_Entry<float> _maxIntensity;

		private static MelonPreferences_Entry<float> _defaultFocus;

		private static MelonPreferences_Entry<float> _focusSensitivity;

		private static MelonPreferences_Entry<float> _focusEaseTau;

		private static MelonPreferences_Entry<float> _focusMaxStep;

		private static MelonPreferences_Entry<float> _focusVelocityGamma;

		private static MelonPreferences_Entry<float> _focusVelocityRefRate;

		private static MelonPreferences_Entry<float> _focusFlickRateMultiplier;

		private static MelonPreferences_Entry<float> _focusVelAttackTau;

		private static MelonPreferences_Entry<float> _focusVelDecayTau;

		private static MelonPreferences_Entry<bool> _invertFocusScroll;

		private static MelonPreferences_Entry<float> _rangeWide;

		private static MelonPreferences_Entry<float> _rangeNarrow;

		private static MelonPreferences_Entry<float> _angleWide;

		private static MelonPreferences_Entry<float> _angleNarrow;

		private static MelonPreferences_Entry<string> _colorHex;

		private static MelonPreferences_Entry<bool> _castShadows;

		private static MelonPreferences_Entry<bool> _remoteBeams;

		private static MelonPreferences_Entry<int> _maxRemoteBeams;

		private static MelonPreferences_Entry<float> _remoteBeamMaxDistance;

		private static MelonPreferences_Entry<int> _remoteShadowNearest;

		private static MelonPreferences_Entry<float> _remoteSmoothingTau;

		private static MelonPreferences_Entry<bool> _suppressRemoteVanillaLights;

		private static MelonPreferences_Entry<bool> _remoteBeamsForUnmoddedPlayers;

		private static MelonPreferences_Entry<bool> _syncMyBeam;

		public static bool Enabled
		{
			get
			{
				return _enabled.Value;
			}
			set
			{
				_enabled.Value = value;
			}
		}

		public static KeyCode FocusModifierKey => ParseKey(_focusModifierKey.Value, (KeyCode)308);

		public static float DefaultIntensity => Mathf.Clamp(_defaultIntensity.Value, MinIntensity, MaxIntensity);

		public static float MinIntensity => Mathf.Max(0.05f, _minIntensity.Value);

		public static float MaxIntensity => Mathf.Max(MinIntensity + 0.1f, _maxIntensity.Value);

		public static float DefaultFocus => Mathf.Clamp01(_defaultFocus.Value);

		public static float FocusSensitivity => Mathf.Clamp(_focusSensitivity.Value, 0.005f, 1f);

		public static float FocusEaseTau => Mathf.Clamp(_focusEaseTau.Value, 0.02f, 0.15f);

		public static float FocusMaxStep => Mathf.Clamp(_focusMaxStep.Value, FocusSensitivity, 1f);

		public static float FocusVelocityGamma => Mathf.Clamp(_focusVelocityGamma.Value, 1f, 4f);

		public static float FocusVelocityRefRate => Mathf.Clamp(_focusVelocityRefRate.Value, 0.5f, 30f);

		public static float FocusFlickRateMultiplier => Mathf.Clamp(_focusFlickRateMultiplier.Value, 1.5f, 10f);

		public static float FocusVelAttackTau => Mathf.Clamp(_focusVelAttackTau.Value, 0.01f, 0.2f);

		public static float FocusVelDecayTau => Mathf.Clamp(_focusVelDecayTau.Value, 0.05f, 0.4f);

		public static bool InvertFocusScroll => _invertFocusScroll.Value;

		public static float RangeWide => Mathf.Clamp(_rangeWide.Value, 3f, 25f);

		public static float RangeNarrow => Mathf.Clamp(_rangeNarrow.Value, 15f, 45f);

		public static float AngleWide => Mathf.Clamp(_angleWide.Value, 40f, 90f);

		public static float AngleNarrow => Mathf.Clamp(_angleNarrow.Value, 8f, 35f);

		public static Color Color => ParseColor(_colorHex.Value, new Color(0.9f, 0.95f, 1f));

		public static bool CastShadows => _castShadows.Value;

		public static bool RemoteBeams => _remoteBeams.Value;

		public static int MaxRemoteBeams => Mathf.Clamp(_maxRemoteBeams.Value, 0, 16);

		public static float RemoteBeamMaxDistance => Mathf.Clamp(_remoteBeamMaxDistance.Value, 10f, 250f);

		public static int RemoteShadowNearest => Mathf.Clamp(_remoteShadowNearest.Value, 0, 4);

		public static float RemoteSmoothingTau => Mathf.Clamp(_remoteSmoothingTau.Value, 0.02f, 0.3f);

		public static bool SuppressRemoteVanillaLights => _suppressRemoteVanillaLights.Value;

		public static bool RemoteBeamsForUnmoddedPlayers => _remoteBeamsForUnmoddedPlayers.Value;

		public static bool SyncMyBeam => _syncMyBeam.Value;

		public static void Initialize()
		{
			_cat = MelonPreferences.CreateCategory("TightBeam");
			_enabled = _cat.CreateEntry<bool>("Enabled", true, (string)null, "Master switch for the whole mod.", false, false, (ValueValidator)null, (string)null);
			_focusModifierKey = _cat.CreateEntry<string>("FocusModifierKey", "LeftAlt", (string)null, "Hold this key and scroll the mouse wheel to adjust FOCUS (Pegel): wide near flood <-> narrow far throw.", false, false, (ValueValidator)null, (string)null);
			_defaultIntensity = _cat.CreateEntry<float>("DefaultIntensity", 7f, (string)null, "Base beam brightness the flashlight rests at (clamped to Min/Max). Not player-adjustable in-game; mods can drive it via the API.", false, false, (ValueValidator)null, (string)null);
			_minIntensity = _cat.CreateEntry<float>("MinIntensity", 1f, (string)null, "Hard floor for brightness (also clamps mod/API overrides).", false, false, (ValueValidator)null, (string)null);
			_maxIntensity = _cat.CreateEntry<float>("MaxIntensity", 20f, (string)null, "Hard ceiling for brightness (also clamps mod/API overrides, so nothing can blind the screen).", false, false, (ValueValidator)null, (string)null);
			_defaultFocus = _cat.CreateEntry<float>("DefaultFocus", 0.5f, (string)null, "Starting focus/Pegel 0..1. 1 = wide short-range flood, 0 = narrow long-range throw, 0.5 = a balanced ~mid beam.", false, false, (ValueValidator)null, (string)null);
			_focusSensitivity = _cat.CreateEntry<float>("FocusSensitivity", 0.08f, (string)null, "Focus change per notch at SLOW/precise scroll speed (the fine-adjustment floor step).", false, false, (ValueValidator)null, (string)null);
			_focusEaseTau = _cat.CreateEntry<float>("FocusEaseTau", 0.05f, (string)null, "Seconds for the displayed beam to ease toward the target focus after a scroll (settle ~4x this). 0.02 = near-instant/steppy, 0.15 = very smooth.", false, false, (ValueValidator)null, (string)null);
			_focusMaxStep = _cat.CreateEntry<float>("FocusMaxStep", 0.35f, (string)null, "Largest per-notch focus step from a fast (but not flick-threshold) scroll.", false, false, (ValueValidator)null, (string)null);
			_focusVelocityGamma = _cat.CreateEntry<float>("FocusVelocityGamma", 2f, (string)null, "Curve exponent shaping how step size ramps up with scroll speed (higher = more ease-in, slow stays fine longer).", false, false, (ValueValidator)null, (string)null);
			_focusVelocityRefRate = _cat.CreateEntry<float>("FocusVelocityRefRate", 5f, (string)null, "Scroll rate (units/sec) at/below which focus changes by plain FocusSensitivity per notch (slow single ticks read ~2-4).", false, false, (ValueValidator)null, (string)null);
			_focusFlickRateMultiplier = _cat.CreateEntry<float>("FocusFlickRateMultiplier", 2f, (string)null, "Flick threshold = FocusVelocityRefRate * this (default 5*2=10); crossing it races focus to the nearest extreme. Fast flicks read ~27+.", false, false, (ValueValidator)null, (string)null);
			_focusVelAttackTau = _cat.CreateEntry<float>("FocusVelAttackTau", 0.05f, (string)null, "How quickly the scroll-speed estimate reacts to a new, faster scroll.", false, false, (ValueValidator)null, (string)null);
			_focusVelDecayTau = _cat.CreateEntry<float>("FocusVelDecayTau", 0.15f, (string)null, "How quickly the scroll-speed estimate cools down once scrolling pauses/stops.", false, false, (ValueValidator)null, (string)null);
			_invertFocusScroll = _cat.CreateEntry<bool>("InvertFocusScroll", false, (string)null, "Flip which scroll direction widens the beam.", false, false, (ValueValidator)null, (string)null);
			_rangeWide = _cat.CreateEntry<float>("RangeWide", 8f, (string)null, "Beam range (m) at full WIDE focus - a short near flood.", false, false, (ValueValidator)null, (string)null);
			_rangeNarrow = _cat.CreateEntry<float>("RangeNarrow", 34f, (string)null, "Beam range (m) at full NARROW focus - a long far throw.", false, false, (ValueValidator)null, (string)null);
			_angleWide = _cat.CreateEntry<float>("AngleWide", 66f, (string)null, "Cone angle (deg) at full WIDE focus.", false, false, (ValueValidator)null, (string)null);
			_angleNarrow = _cat.CreateEntry<float>("AngleNarrow", 16f, (string)null, "Cone angle (deg) at full NARROW focus.", false, false, (ValueValidator)null, (string)null);
			_colorHex = _cat.CreateEntry<string>("ColorHex", "#E6F2FF", (string)null, "Beam colour (hex). Cool white by default so it reads against warm/sickly environments.", false, false, (ValueValidator)null, (string)null);
			_castShadows = _cat.CreateEntry<bool>("CastShadows", true, (string)null, "Cast soft shadows so the beam is blocked by walls (turn off on low-end machines).", false, false, (ValueValidator)null, (string)null);
			_remoteBeams = _cat.CreateEntry<bool>("RemoteBeams", true, (string)null, "In co-op, show other players' flashlights as proper TightBeam cones instead of the game's small point light.", false, false, (ValueValidator)null, (string)null);
			_maxRemoteBeams = _cat.CreateEntry<int>("MaxRemoteBeams", 4, (string)null, "Most other players' beams drawn at once (nearest first). 0 turns remote beams off.", false, false, (ValueValidator)null, (string)null);
			_remoteBeamMaxDistance = _cat.CreateEntry<float>("RemoteBeamMaxDistance", 70f, (string)null, "Metres beyond which another player's beam is not drawn.", false, false, (ValueValidator)null, (string)null);
			_remoteShadowNearest = _cat.CreateEntry<int>("RemoteShadowNearest", 0, (string)null, "How many of the nearest remote beams may cast shadows. 0 = none, which keeps a full lobby smooth.", false, false, (ValueValidator)null, (string)null);
			_remoteSmoothingTau = _cat.CreateEntry<float>("RemoteSmoothingTau", 0.08f, (string)null, "Smoothing on another player's beam aim. The game replicates their camera about 10x/sec, so without this the cone steps visibly.", false, false, (ValueValidator)null, (string)null);
			_suppressRemoteVanillaLights = _cat.CreateEntry<bool>("SuppressRemoteVanillaLights", true, (string)null, "Turn off another player's vanilla flashlight lights while their TightBeam cone is shown, so you never see both at once.", false, false, (ValueValidator)null, (string)null);
			_remoteBeamsForUnmoddedPlayers = _cat.CreateEntry<bool>("RemoteBeamsForUnmoddedPlayers", true, (string)null, "Also draw a cone for players who do not have TightBeam, using your own default settings. Turn off to leave their vanilla flashlight alone.", false, false, (ValueValidator)null, (string)null);
			_syncMyBeam = _cat.CreateEntry<bool>("SyncMyBeam", true, (string)null, "Share your beam's shape, colour and effects with the other players, so they see your flashlight the way you do.", false, false, (ValueValidator)null, (string)null);
		}

		private static KeyCode ParseKey(string s, KeyCode fallback)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (!Enum.TryParse<KeyCode>(s, ignoreCase: true, out KeyCode result))
			{
				return fallback;
			}
			return result;
		}

		private static Color ParseColor(string input, Color fallback)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(input))
			{
				return fallback;
			}
			Color result = default(Color);
			if (ColorUtility.TryParseHtmlString(input.StartsWith("#") ? input : ("#" + input), ref result))
			{
				return result;
			}
			return fallback;
		}
	}
}
namespace TightBeam.Bridge
{
	internal static class BridgeHost
	{
		private static readonly List<Action<bool>> _toggleListeners = new List<Action<bool>>();

		public static void Install()
		{
			FlashlightController c = FlashlightController.Instance;
			FlashlightBridge.IsOn = () => c.IsOn;
			FlashlightBridge.GetIntensity = () => c.CurrentIntensity;
			FlashlightBridge.GetRange = () => c.CurrentRange;
			FlashlightBridge.GetSpotAngle = () => c.CurrentSpotAngle;
			FlashlightBridge.GetColor = delegate
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: 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_001d: 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_002f: Unknown result type (might be due to invalid IL or missing references)
				Color currentColor = c.CurrentColor;
				return new float[4] { currentColor.r, currentColor.g, currentColor.b, currentColor.a };
			};
			FlashlightBridge.SetOn = delegate(bool on)
			{
				c.SetOn(on);
			};
			FlashlightBridge.Toggle = delegate
			{
				c.Toggle();
			};
			FlashlightBridge.SetIntensity = delegate(float v)
			{
				c.SetIntensity(v);
			};
			FlashlightBridge.SetRange = delegate(float v)
			{
				c.SetBaseRange(v);
			};
			FlashlightBridge.SetSpotAngle = delegate(float v)
			{
				c.SetBaseSpotAngle(v);
			};
			FlashlightBridge.SetColor = delegate(float r, float g, float b, float a)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				c.SetColor(new Color(r, g, b, a));
			};
			FlashlightBridge.Blink = delegate(int t, float i)
			{
				c.Blink(t, i);
			};
			FlashlightBridge.Flicker = delegate(float s, float d, float f)
			{
				c.Flicker(s, d, f);
			};
			FlashlightBridge.StopFlicker = delegate
			{
				c.StopFlicker();
			};
			FlashlightBridge.Pulse = delegate(float a, float p, float d)
			{
				c.Pulse(a, p, d);
			};
			FlashlightBridge.StopPulse = delegate
			{
				c.StopPulse();
			};
			FlashlightBridge.TempIntensity = delegate(float v, float s)
			{
				c.TemporaryIntensity(v, s);
			};
			FlashlightBridge.TempColor = delegate(float r, float g, float b, float a, float s)
			{
				c.TemporaryColor(r, g, b, a, s);
			};
			FlashlightBridge.BeginOverride = (string owner) => c.BeginOverride(owner);
			FlashlightBridge.EndOverride = delegate(int tok)
			{
				c.EndOverride(tok);
			};
			FlashlightBridge.OvIntensity = delegate(int tok, float v)
			{
				c.OverrideIntensity(tok, v);
			};
			FlashlightBridge.OvRange = delegate(int tok, float v)
			{
				c.OverrideRange(tok, v);
			};
			FlashlightBridge.OvSpotAngle = delegate(int tok, float v)
			{
				c.OverrideSpotAngle(tok, v);
			};
			FlashlightBridge.OvColor = delegate(int tok, float r, float g, float b, float a)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				c.OverrideColor(tok, new Color(r, g, b, a));
			};
			FlashlightBridge.ClrIntensity = delegate(int tok)
			{
				c.ClearOverrideIntensity(tok);
			};
			FlashlightBridge.ClrRange = delegate(int tok)
			{
				c.ClearOverrideRange(tok);
			};
			FlashlightBridge.ClrSpotAngle = delegate(int tok)
			{
				c.ClearOverrideSpotAngle(tok);
			};
			FlashlightBridge.ClrColor = delegate(int tok)
			{
				c.ClearOverrideColor(tok);
			};
			FlashlightBridge.RegisterToggledListener = delegate(Action<bool> cb)
			{
				if (cb != null)
				{
					_toggleListeners.Add(cb);
				}
			};
			c.Toggled += delegate(bool on)
			{
				for (int i = 0; i < _toggleListeners.Count; i++)
				{
					try
					{
						_toggleListeners[i](on);
					}
					catch
					{
					}
				}
			};
			FlashlightBridge.IsMultiplayer = () => RemoteBeams.InMultiplayer();
			FlashlightBridge.GetLocalSteamId = () => PlayerIdentity.LocalSteamId();
			FlashlightBridge.GetRemoteBeamIds = () => RemoteBeams.RemoteIds();
			FlashlightBridge.RemoteHasTightBeam = (ulong id) => RemoteBeams.HasSyncedBeam(id);
			FlashlightBridge.GetRemoteBeam = (ulong id) => RemoteBeams.BeamOf(id);
			FlashlightBridge.GetRemoteBeamPose = (ulong id) => RemoteBeams.PoseOf(id);
			FlashlightBridge.IsRemoteBeamRendered = (ulong id) => RemoteBeams.IsRendered(id);
			FlashlightBridge.RegisterRemoteToggledListener = delegate(Action<ulong, bool> cb)
			{
				RemoteBeams.AddToggledListener(cb);
			};
		}
	}
	public static class FlashlightBridge
	{
		public const int AbiVersion = 2;

		public static Func<bool> IsOn;

		public static Func<float> GetIntensity;

		public static Func<float> GetRange;

		public static Func<float> GetSpotAngle;

		public static Func<float[]> GetColor;

		public static Action<bool> SetOn;

		public static Action Toggle;

		public static Action<float> SetIntensity;

		public static Action<float> SetRange;

		public static Action<float> SetSpotAngle;

		public static Action<float, float, float, float> SetColor;

		public static Action<int, float> Blink;

		public static Action<float, float, float> Flicker;

		public static Action StopFlicker;

		public static Action<float, float, float> Pulse;

		public static Action StopPulse;

		public static Action<float, float> TempIntensity;

		public static Action<float, float, float, float, float> TempColor;

		public static Func<string, int> BeginOverride;

		public static Action<int> EndOverride;

		public static Action<int, float> OvIntensity;

		public static Action<int, float> OvRange;

		public static Action<int, float> OvSpotAngle;

		public static Action<int, float, float, float, float> OvColor;

		public static Action<int> ClrIntensity;

		public static Action<int> ClrRange;

		public static Action<int> ClrSpotAngle;

		public static Action<int> ClrColor;

		public static Action<Action<bool>> RegisterToggledListener;

		public static Func<bool> IsMultiplayer;

		public static Func<ulong> GetLocalSteamId;

		public static Func<ulong[]> GetRemoteBeamIds;

		public static Func<ulong, bool> RemoteHasTightBeam;

		public static Func<ulong, float[]> GetRemoteBeam;

		public static Func<ulong, float[]> GetRemoteBeamPose;

		public static Func<ulong, bool> IsRemoteBeamRendered;

		public static Action<Action<ulong, bool>> RegisterRemoteToggledListener;
	}
}