Decompiled source of LampToggle v1.0.0

plugins/LampToggle/LampToggle.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalCompanyInputUtils.Api;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;

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

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace LampToggle
{
	[BepInPlugin("lc.lamptoggle", "LampToggle", "2.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PLUGIN_GUID = "lc.lamptoggle";

		public const string PLUGIN_NAME = "LampToggle";

		public const string PLUGIN_VERSION = "2.0.1";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal static InputActions Actions;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Actions = new InputActions();
			_harmony = new Harmony("lc.lamptoggle");
			_harmony.PatchAll();
			Log.LogInfo((object)"LampToggle v2.0.1 loaded.");
		}
	}
	public class InputActions : LcInputActions
	{
		[InputAction("<Keyboard>/f", Name = "Toggle Last Light")]
		public InputAction ToggleLightKey { get; set; }
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal static class PlayerControllerBPatch
	{
		private enum LightKind
		{
			None,
			Handlamp,
			VanillaFlashlight
		}

		private struct LightSearchResult
		{
			public GrabbableObject? Item;

			public int SlotIndex;

			public bool IsCurrentlyHeld;

			public LightKind Kind;
		}

		private static int _lastLightSlot = -1;

		private static string? _lastLightTypeName;

		private static string? _lastLightItemName;

		private static LightKind _lastLightKind = LightKind.None;

		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		private static void OnUpdate(PlayerControllerB __instance)
		{
			try
			{
				if (!ShouldHandleInput(__instance))
				{
					return;
				}
				RememberCurrentlyHeldLight(__instance);
				MaintainHeldLightState(__instance);
				MaintainPocketLightBatteryState(__instance);
				if (Plugin.Actions.ToggleLightKey.WasPressedThisFrame())
				{
					LightSearchResult result = ResolveTargetLight(__instance);
					if (!((Object)(object)result.Item == (Object)null))
					{
						ToggleResolvedLight(__instance, result);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Error in PlayerControllerBPatch.OnUpdate: {arg}");
			}
		}

		private static bool ShouldHandleInput(PlayerControllerB player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (!((NetworkBehaviour)player).IsOwner)
			{
				return false;
			}
			if (!player.isPlayerControlled)
			{
				return false;
			}
			if (player.inTerminalMenu)
			{
				return false;
			}
			if (player.isTypingChat)
			{
				return false;
			}
			if (player.isTestingPlayer)
			{
				return false;
			}
			return true;
		}

		private static void RememberCurrentlyHeldLight(PlayerControllerB player)
		{
			if (player.ItemSlots == null || player.ItemSlots.Length == 0)
			{
				return;
			}
			int currentItemSlot = player.currentItemSlot;
			if (currentItemSlot < 0 || currentItemSlot >= player.ItemSlots.Length)
			{
				return;
			}
			GrabbableObject val = player.ItemSlots[currentItemSlot];
			if (!((Object)(object)val == (Object)null))
			{
				LightKind lightKind = GetLightKind(val);
				if (lightKind != 0)
				{
					_lastLightSlot = currentItemSlot;
					_lastLightKind = lightKind;
					_lastLightTypeName = ((object)val).GetType().FullName ?? ((object)val).GetType().Name;
					_lastLightItemName = (((Object)(object)val.itemProperties != (Object)null) ? val.itemProperties.itemName : null);
				}
			}
		}

		private static void MaintainHeldLightState(PlayerControllerB player)
		{
			try
			{
				if (player.ItemSlots == null || player.ItemSlots.Length == 0)
				{
					return;
				}
				int currentItemSlot = player.currentItemSlot;
				if (currentItemSlot < 0 || currentItemSlot >= player.ItemSlots.Length)
				{
					return;
				}
				GrabbableObject val = player.ItemSlots[currentItemSlot];
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				LightKind lightKind = GetLightKind(val);
				if (lightKind != 0)
				{
					bool boolFieldOrProperty = GetBoolFieldOrProperty(val, "isBeingUsed");
					if (lightKind == LightKind.Handlamp)
					{
						MaintainHeldHandlampState(val, boolFieldOrProperty);
					}
					else if (lightKind == LightKind.VanillaFlashlight && boolFieldOrProperty)
					{
						SyncPlayerHelmetLight(player, enabled: true, val);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"MaintainHeldLightState failed: {arg}");
			}
		}

		private static void MaintainPocketLightBatteryState(PlayerControllerB player)
		{
			try
			{
				if (player.ItemSlots == null || player.ItemSlots.Length == 0)
				{
					return;
				}
				for (int i = 0; i < player.ItemSlots.Length; i++)
				{
					if (i == player.currentItemSlot)
					{
						continue;
					}
					GrabbableObject val = player.ItemSlots[i];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					LightKind lightKind = GetLightKind(val);
					if (lightKind != 0 && GetBoolFieldOrProperty(val, "isBeingUsed") && !CanTurnOnLight(val))
					{
						switch (lightKind)
						{
						case LightKind.Handlamp:
							ForcePocketHandlampState(val, enabled: false);
							break;
						case LightKind.VanillaFlashlight:
							SetBoolFieldOrProperty(val, "isBeingUsed", value: false);
							SyncPlayerHelmetLight(player, enabled: false, val);
							break;
						}
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"MaintainPocketLightBatteryState failed: {arg}");
			}
		}

		private static void MaintainHeldHandlampState(GrabbableObject item, bool enabled)
		{
			try
			{
				TryInvokeNoArgMethod(item, "InitializeComponents");
				SetBoolFieldOrProperty(item, "isBeingUsed", enabled);
				SetBoolFieldOrProperty(item, "previouslightstate", enabled);
				SetNamedLightEnabled(item, "pocketLight", enabled);
				SetNamedLightEnabled(item, "helmetLight", enabled);
				if (enabled)
				{
					EnableAllChildLights(item);
				}
				else
				{
					DisableAllChildLights(item);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"MaintainHeldHandlampState failed: {arg}");
			}
		}

		private static LightSearchResult ResolveTargetLight(PlayerControllerB player)
		{
			LightSearchResult result = FindHeldLight(player);
			if ((Object)(object)result.Item != (Object)null)
			{
				UpdateLastTrackedLight(result);
				return result;
			}
			LightSearchResult result2 = FindRememberedLight(player);
			if ((Object)(object)result2.Item != (Object)null)
			{
				return result2;
			}
			LightSearchResult result3 = FindFirstSupportedLight(player);
			if ((Object)(object)result3.Item != (Object)null)
			{
				UpdateLastTrackedLight(result3);
				return result3;
			}
			return EmptyResult();
		}

		private static LightSearchResult FindHeldLight(PlayerControllerB player)
		{
			if (player.ItemSlots == null || player.ItemSlots.Length == 0)
			{
				return EmptyResult();
			}
			int currentItemSlot = player.currentItemSlot;
			if (currentItemSlot < 0 || currentItemSlot >= player.ItemSlots.Length)
			{
				return EmptyResult();
			}
			GrabbableObject val = player.ItemSlots[currentItemSlot];
			if ((Object)(object)val == (Object)null)
			{
				return EmptyResult();
			}
			LightKind lightKind = GetLightKind(val);
			if (lightKind == LightKind.None)
			{
				return EmptyResult();
			}
			return BuildResult(val, currentItemSlot, isHeld: true, lightKind);
		}

		private static LightSearchResult FindRememberedLight(PlayerControllerB player)
		{
			if (player.ItemSlots == null || player.ItemSlots.Length == 0)
			{
				return EmptyResult();
			}
			if (_lastLightSlot < 0 || _lastLightSlot >= player.ItemSlots.Length)
			{
				return EmptyResult();
			}
			GrabbableObject val = player.ItemSlots[_lastLightSlot];
			if ((Object)(object)val == (Object)null)
			{
				return EmptyResult();
			}
			LightKind lightKind = GetLightKind(val);
			if (lightKind == LightKind.None)
			{
				return EmptyResult();
			}
			string? a = ((object)val).GetType().FullName ?? ((object)val).GetType().Name;
			string a2 = (((Object)(object)val.itemProperties != (Object)null) ? val.itemProperties.itemName : null);
			if (!string.Equals(a, _lastLightTypeName, StringComparison.Ordinal) || !string.Equals(a2, _lastLightItemName, StringComparison.Ordinal) || lightKind != _lastLightKind)
			{
				return EmptyResult();
			}
			return BuildResult(val, _lastLightSlot, player.currentItemSlot == _lastLightSlot, lightKind);
		}

		private static LightSearchResult FindFirstSupportedLight(PlayerControllerB player)
		{
			if (player.ItemSlots == null || player.ItemSlots.Length == 0)
			{
				return EmptyResult();
			}
			for (int i = 0; i < player.ItemSlots.Length; i++)
			{
				GrabbableObject val = player.ItemSlots[i];
				if (!((Object)(object)val == (Object)null))
				{
					LightKind lightKind = GetLightKind(val);
					if (lightKind != 0)
					{
						return BuildResult(val, i, player.currentItemSlot == i, lightKind);
					}
				}
			}
			return EmptyResult();
		}

		private static LightSearchResult BuildResult(GrabbableObject item, int slotIndex, bool isHeld, LightKind kind)
		{
			LightSearchResult result = default(LightSearchResult);
			result.Item = item;
			result.SlotIndex = slotIndex;
			result.IsCurrentlyHeld = isHeld;
			result.Kind = kind;
			return result;
		}

		private static LightSearchResult EmptyResult()
		{
			LightSearchResult result = default(LightSearchResult);
			result.Item = null;
			result.SlotIndex = -1;
			result.IsCurrentlyHeld = false;
			result.Kind = LightKind.None;
			return result;
		}

		private static void UpdateLastTrackedLight(LightSearchResult result)
		{
			if (!((Object)(object)result.Item == (Object)null))
			{
				_lastLightSlot = result.SlotIndex;
				_lastLightKind = result.Kind;
				_lastLightTypeName = ((object)result.Item).GetType().FullName ?? ((object)result.Item).GetType().Name;
				_lastLightItemName = (((Object)(object)result.Item.itemProperties != (Object)null) ? result.Item.itemProperties.itemName : null);
			}
		}

		private static LightKind GetLightKind(GrabbableObject item)
		{
			Type type = ((object)item).GetType();
			string text = type.FullName ?? type.Name;
			string text2 = (((Object)(object)item.itemProperties != (Object)null) ? item.itemProperties.itemName : null);
			if (text == "UsualScrap.Behaviors.HandlampScript")
			{
				return LightKind.Handlamp;
			}
			if (text == "FlashlightItem")
			{
				return LightKind.VanillaFlashlight;
			}
			if (!string.IsNullOrEmpty(text2))
			{
				if (text2.IndexOf("handlamp", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return LightKind.Handlamp;
				}
				if (string.Equals(text2, "Flashlight", StringComparison.OrdinalIgnoreCase))
				{
					return LightKind.VanillaFlashlight;
				}
				if (string.Equals(text2, "Pro-flashlight", StringComparison.OrdinalIgnoreCase))
				{
					return LightKind.VanillaFlashlight;
				}
				if (string.Equals(text2, "Pro flashlight", StringComparison.OrdinalIgnoreCase))
				{
					return LightKind.VanillaFlashlight;
				}
				if (string.Equals(text2, "Golden flashlight", StringComparison.OrdinalIgnoreCase))
				{
					return LightKind.VanillaFlashlight;
				}
				if (text2.IndexOf("flashlight", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return LightKind.VanillaFlashlight;
				}
			}
			return LightKind.None;
		}

		private static void ToggleResolvedLight(PlayerControllerB player, LightSearchResult result)
		{
			if ((Object)(object)result.Item == (Object)null)
			{
				return;
			}
			bool flag = !GetBoolFieldOrProperty(result.Item, "isBeingUsed");
			if (!flag || CanTurnOnLight(result.Item))
			{
				switch (result.Kind)
				{
				case LightKind.Handlamp:
					ToggleHandlamp(result, flag);
					break;
				case LightKind.VanillaFlashlight:
					ToggleVanillaFlashlight(player, result, flag);
					break;
				}
				UpdateLastTrackedLight(result);
			}
		}

		private static void ToggleHandlamp(LightSearchResult result, bool targetState)
		{
			if ((Object)(object)result.Item == (Object)null)
			{
				return;
			}
			if (result.IsCurrentlyHeld)
			{
				if (!targetState || CanTurnOnLight(result.Item))
				{
					if (TryInvokeItemActivate(result.Item, targetState))
					{
						SyncHeldHandlampStateAfterSuccessfulToggle(result.Item, targetState);
					}
					else
					{
						Plugin.Log.LogWarning((object)"Held Handlamp: ItemActivate failed.");
					}
				}
			}
			else
			{
				ForcePocketHandlampState(result.Item, targetState);
			}
		}

		private static void ToggleVanillaFlashlight(PlayerControllerB player, LightSearchResult result, bool targetState)
		{
			if ((Object)(object)result.Item == (Object)null)
			{
				return;
			}
			if (result.IsCurrentlyHeld)
			{
				if (!targetState || CanTurnOnLight(result.Item))
				{
					if (TryInvokeItemActivate(result.Item, targetState))
					{
						SetBoolFieldOrProperty(result.Item, "isBeingUsed", targetState);
						SyncPlayerHelmetLight(player, targetState, result.Item);
					}
					else
					{
						Plugin.Log.LogWarning((object)"Held vanilla flashlight: ItemActivate failed.");
					}
				}
			}
			else
			{
				TryTogglePocketFlashlightRpc(player, targetState);
				SetBoolFieldOrProperty(result.Item, "isBeingUsed", targetState);
				SyncPlayerHelmetLight(player, targetState, result.Item);
				PlayPocketVanillaFlashlightToggleSound(result.Item, targetState);
			}
		}

		private static bool CanTurnOnLight(GrabbableObject item)
		{
			try
			{
				if (!GetBoolFieldOrProperty(GetFieldOrPropertyObject(item, "itemProperties"), "requiresBattery"))
				{
					return true;
				}
				object fieldOrPropertyObject = GetFieldOrPropertyObject(item, "insertedBattery");
				if (fieldOrPropertyObject == null)
				{
					return false;
				}
				return GetFloatFieldOrProperty(fieldOrPropertyObject, "charge") > 0.0001f;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"CanTurnOnLight failed: {arg}");
				return true;
			}
		}

		private static void SyncHeldHandlampStateAfterSuccessfulToggle(GrabbableObject item, bool state)
		{
			try
			{
				TryInvokeNoArgMethod(item, "InitializeComponents");
				SetBoolFieldOrProperty(item, "isBeingUsed", state);
				SetBoolFieldOrProperty(item, "previouslightstate", state);
				SetNamedLightEnabled(item, "pocketLight", state);
				SetNamedLightEnabled(item, "helmetLight", state);
				if (state)
				{
					EnableAllChildLights(item);
				}
				else
				{
					DisableAllChildLights(item);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"SyncHeldHandlampStateAfterSuccessfulToggle failed: {arg}");
			}
		}

		private static void ForcePocketHandlampState(GrabbableObject item, bool enabled)
		{
			try
			{
				TryInvokeNoArgMethod(item, "InitializeComponents");
				SetBoolFieldOrProperty(item, "isBeingUsed", enabled);
				SetBoolFieldOrProperty(item, "previouslightstate", enabled);
				if (enabled)
				{
					ApplyPocketHandlampEnable(item);
				}
				else
				{
					ApplyPocketHandlampDisable(item);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"ForcePocketHandlampState failed: {arg}");
			}
		}

		private static void ApplyPocketHandlampEnable(GrabbableObject item)
		{
			if (TryInvokeFlexibleBoolMethod(item, "ToggleLights", value: true))
			{
				SetNamedLightEnabled(item, "pocketLight", enabled: true);
				SetNamedLightEnabled(item, "helmetLight", enabled: true);
				DisableHandlampHeldOnlyLightsIfPocketLightsExist(item);
				return;
			}
			if (TryInvokeNoArgMethod(item, "ToggleLights"))
			{
				SetNamedLightEnabled(item, "pocketLight", enabled: true);
				SetNamedLightEnabled(item, "helmetLight", enabled: true);
				DisableHandlampHeldOnlyLightsIfPocketLightsExist(item);
				return;
			}
			SetNamedLightEnabled(item, "pocketLight", enabled: true);
			SetNamedLightEnabled(item, "helmetLight", enabled: true);
			TryInvokeFlexibleBoolMethod(item, "ToggleStateClientRpc", value: true);
			TryInvokeFlexibleBoolMethod(item, "ToggleStateServerRpc", value: true);
			TryInvokeFlexibleBoolMethod(item, "ToggleCoroutineServerRpc", value: true);
			TryInvokeFlexibleBoolMethod(item, "ToggleCoroutine", value: true);
			TryInvokeFlexibleBoolMethod(item, "ToggleState", value: true);
			DisableHandlampHeldOnlyLightsIfPocketLightsExist(item);
		}

		private static void ApplyPocketHandlampDisable(GrabbableObject item)
		{
			if (!TryInvokeFlexibleBoolMethod(item, "ToggleLights", value: false))
			{
				TryInvokeNoArgMethod(item, "ToggleLights");
			}
			SetNamedLightEnabled(item, "pocketLight", enabled: false);
			SetNamedLightEnabled(item, "helmetLight", enabled: false);
			TryInvokeFlexibleBoolMethod(item, "ToggleStateClientRpc", value: false);
			TryInvokeFlexibleBoolMethod(item, "ToggleStateServerRpc", value: false);
			TryInvokeFlexibleBoolMethod(item, "ToggleCoroutineServerRpc", value: false);
			TryInvokeFlexibleBoolMethod(item, "ToggleCoroutine", value: false);
			TryInvokeFlexibleBoolMethod(item, "ToggleState", value: false);
			DisableAllChildLights(item);
		}

		private static void DisableHandlampHeldOnlyLightsIfPocketLightsExist(GrabbableObject item)
		{
			try
			{
				object? fieldOrPropertyObject = GetFieldOrPropertyObject(item, "pocketLight");
				Light val = (Light)((fieldOrPropertyObject is Light) ? fieldOrPropertyObject : null);
				object? fieldOrPropertyObject2 = GetFieldOrPropertyObject(item, "helmetLight");
				Light val2 = (Light)((fieldOrPropertyObject2 is Light) ? fieldOrPropertyObject2 : null);
				if (!((Object)(object)val != (Object)null) && !((Object)(object)val2 != (Object)null))
				{
					return;
				}
				Light[] componentsInChildren = ((Component)item).GetComponentsInChildren<Light>(true);
				foreach (Light val3 in componentsInChildren)
				{
					if (!((Object)(object)val3 == (Object)null) && val3 != val && val3 != val2)
					{
						((Behaviour)val3).enabled = false;
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"DisableHandlampHeldOnlyLightsIfPocketLightsExist failed: {arg}");
			}
		}

		private static void EnableAllChildLights(GrabbableObject item)
		{
			try
			{
				Light[] componentsInChildren = ((Component)item).GetComponentsInChildren<Light>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					((Behaviour)componentsInChildren[i]).enabled = true;
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"EnableAllChildLights failed: {arg}");
			}
		}

		private static bool TryTogglePocketFlashlightRpc(PlayerControllerB player, bool enabled)
		{
			try
			{
				MethodInfo[] array = (from m in typeof(PlayerControllerB).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
					where m.Name == "PocketFlashlightServerRpc"
					select m).ToArray();
				foreach (MethodInfo methodInfo in array)
				{
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length == 1 && parameters[0].ParameterType == typeof(bool))
					{
						methodInfo.Invoke(player, new object[1] { enabled });
						return true;
					}
					if (parameters.Length == 0)
					{
						methodInfo.Invoke(player, Array.Empty<object>());
						return true;
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"TryTogglePocketFlashlightRpc failed: {arg}");
			}
			return false;
		}

		private static void SyncPlayerHelmetLight(PlayerControllerB player, bool enabled, GrabbableObject sourceItem)
		{
			try
			{
				SetBoolFieldOrProperty(player, "pocketedFlashlight", enabled);
				SetBoolFieldOrProperty(player, "usingPlayerHelmetLight", enabled);
				object? fieldOrPropertyObject = GetFieldOrPropertyObject(player, "helmetLight");
				Light val = (Light)((fieldOrPropertyObject is Light) ? fieldOrPropertyObject : null);
				if (!((Object)(object)val == (Object)null))
				{
					if (enabled)
					{
						CopyBestFlashlightLightToHelmetLight(sourceItem, val);
					}
					((Behaviour)val).enabled = enabled;
					if (((Component)val).gameObject.activeSelf != enabled)
					{
						((Component)val).gameObject.SetActive(enabled);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"SyncPlayerHelmetLight failed: {arg}");
			}
		}

		private static void CopyBestFlashlightLightToHelmetLight(GrabbableObject sourceItem, Light helmetLight)
		{
			try
			{
				Light val = FindBestSourceLightFromItem(sourceItem);
				if (!((Object)(object)val == (Object)null))
				{
					CopyLightSettings(val, helmetLight);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"CopyBestFlashlightLightToHelmetLight failed: {arg}");
			}
		}

		private static Light? FindBestSourceLightFromItem(GrabbableObject item)
		{
			try
			{
				string[] array = new string[7] { "flashlightBulb", "flashlightLight", "bulbLight", "mainLight", "spotLight", "flashlightSpot", "flashlightBeam" };
				foreach (string name in array)
				{
					object? fieldOrPropertyObject = GetFieldOrPropertyObject(item, name);
					Light val = (Light)((fieldOrPropertyObject is Light) ? fieldOrPropertyObject : null);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
				Light[] componentsInChildren = ((Component)item).GetComponentsInChildren<Light>(true);
				if (componentsInChildren.Length == 0)
				{
					return null;
				}
				Light val2 = componentsInChildren.Where((Light l) => (Object)(object)l != (Object)null && (int)l.type == 0).OrderByDescending(GetLightScore).FirstOrDefault();
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
				return componentsInChildren.Where((Light l) => (Object)(object)l != (Object)null).OrderByDescending(GetLightScore).FirstOrDefault();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"FindBestSourceLightFromItem failed: {arg}");
				return null;
			}
		}

		private static float GetLightScore(Light light)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			num += light.intensity * 10f;
			num += light.range;
			num += light.spotAngle * 0.25f;
			if ((int)light.type == 0)
			{
				num += 1000f;
			}
			return num;
		}

		private static void CopyLightSettings(Light source, Light destination)
		{
			//IL_0002: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			destination.type = source.type;
			destination.color = source.color;
			destination.colorTemperature = source.colorTemperature;
			destination.useColorTemperature = source.useColorTemperature;
			destination.intensity = source.intensity;
			destination.range = source.range;
			destination.spotAngle = source.spotAngle;
			destination.innerSpotAngle = source.innerSpotAngle;
			destination.shadows = source.shadows;
			destination.shadowStrength = source.shadowStrength;
			destination.shadowBias = source.shadowBias;
			destination.shadowNormalBias = source.shadowNormalBias;
			destination.shadowNearPlane = source.shadowNearPlane;
			destination.cookie = source.cookie;
			destination.cookieSize = source.cookieSize;
			destination.renderMode = source.renderMode;
			destination.cullingMask = source.cullingMask;
			destination.bounceIntensity = source.bounceIntensity;
			destination.lightShadowCasterMode = source.lightShadowCasterMode;
			try
			{
				destination.shape = source.shape;
			}
			catch
			{
			}
		}

		private static void PlayPocketVanillaFlashlightToggleSound(GrabbableObject item, bool enabled)
		{
			try
			{
				AudioSource val = FindBestAudioSource(item);
				if (!((Object)(object)val == (Object)null))
				{
					AudioClip val2 = FindBestVanillaFlashlightToggleClip(item, val, enabled);
					if ((Object)(object)val2 != (Object)null)
					{
						val.PlayOneShot(val2);
					}
					else if ((Object)(object)val.clip != (Object)null)
					{
						val.Play();
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"PlayPocketVanillaFlashlightToggleSound failed: {arg}");
			}
		}

		private static AudioSource? FindBestAudioSource(GrabbableObject item)
		{
			string[] array = new string[5] { "flashlightAudio", "flashLightAudio", "itemAudio", "audioSource", "thisAudio" };
			foreach (string name in array)
			{
				object? fieldOrPropertyObject = GetFieldOrPropertyObject(item, name);
				AudioSource val = (AudioSource)((fieldOrPropertyObject is AudioSource) ? fieldOrPropertyObject : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			AudioSource[] componentsInChildren = ((Component)item).GetComponentsInChildren<AudioSource>(true);
			if (componentsInChildren.Length != 0)
			{
				return componentsInChildren[0];
			}
			return ((Component)item).GetComponent<AudioSource>();
		}

		private static AudioClip? FindBestVanillaFlashlightToggleClip(GrabbableObject item, AudioSource source, bool enabled)
		{
			string preferredName = (enabled ? "on" : "off");
			string[] array = new string[5]
			{
				enabled ? "flashlightTurnOnSound" : "flashlightTurnOffSound",
				enabled ? "switchOnAudio" : "switchOffAudio",
				enabled ? "turnOnSound" : "turnOffSound",
				enabled ? "lightOnSound" : "lightOffSound",
				enabled ? "useUpSFX" : "useDownSFX"
			};
			foreach (string name in array)
			{
				object? fieldOrPropertyObject = GetFieldOrPropertyObject(item, name);
				AudioClip val = (AudioClip)((fieldOrPropertyObject is AudioClip) ? fieldOrPropertyObject : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			array = new string[5] { "flashlightClips", "flashlightSounds", "toggleClips", "toggleSounds", "audioClips" };
			foreach (string name2 in array)
			{
				if (!(GetFieldOrPropertyObject(item, name2) is AudioClip[] array2) || array2.Length == 0)
				{
					continue;
				}
				AudioClip val2 = ((IEnumerable<AudioClip>)array2).FirstOrDefault((Func<AudioClip, bool>)((AudioClip c) => (Object)(object)c != (Object)null && ((Object)c).name != null && ((Object)c).name.IndexOf(preferredName, StringComparison.OrdinalIgnoreCase) >= 0));
				if ((Object)(object)val2 != (Object)null)
				{
					return val2;
				}
				if (array2.Length >= 2)
				{
					if (!enabled)
					{
						return array2[1];
					}
					return array2[0];
				}
				return array2[0];
			}
			if ((Object)(object)source.clip != (Object)null)
			{
				return source.clip;
			}
			return null;
		}

		private static bool TryInvokeItemActivate(GrabbableObject item, bool used)
		{
			try
			{
				MethodInfo method = ((object)item).GetType().GetMethod("ItemActivate", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
				{
					typeof(bool),
					typeof(bool)
				}, null);
				if (method != null)
				{
					method.Invoke(item, new object[2] { used, true });
					return true;
				}
				MethodInfo method2 = ((object)item).GetType().GetMethod("ItemActivate", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(bool) }, null);
				if (method2 != null)
				{
					method2.Invoke(item, new object[1] { used });
					return true;
				}
				return false;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"TryInvokeItemActivate failed: {arg}");
				return false;
			}
		}

		private static bool TryInvokeFlexibleBoolMethod(object instance, string methodName, bool value)
		{
			string methodName2 = methodName;
			try
			{
				MethodInfo[] array = (from m in instance.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
					where m.Name == methodName2
					select m).ToArray();
				foreach (MethodInfo methodInfo in array)
				{
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length == 1 && parameters[0].ParameterType == typeof(bool))
					{
						methodInfo.Invoke(instance, new object[1] { value });
						return true;
					}
					if (parameters.Length == 0)
					{
						methodInfo.Invoke(instance, Array.Empty<object>());
						return true;
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"TryInvokeFlexibleBoolMethod({methodName2}) failed: {arg}");
			}
			return false;
		}

		private static bool TryInvokeNoArgMethod(object instance, string methodName)
		{
			try
			{
				MethodInfo method = instance.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
				if (method == null)
				{
					return false;
				}
				method.Invoke(instance, Array.Empty<object>());
				return true;
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"TryInvokeNoArgMethod({methodName}) failed: {arg}");
				return false;
			}
		}

		private static void SetNamedLightEnabled(object instance, string fieldOrPropertyName, bool enabled)
		{
			try
			{
				object? fieldOrPropertyObject = GetFieldOrPropertyObject(instance, fieldOrPropertyName);
				Light val = (Light)((fieldOrPropertyObject is Light) ? fieldOrPropertyObject : null);
				if ((Object)(object)val != (Object)null)
				{
					((Behaviour)val).enabled = enabled;
					if (((Component)val).gameObject.activeSelf != enabled)
					{
						((Component)val).gameObject.SetActive(enabled);
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"SetNamedLightEnabled({fieldOrPropertyName}) failed: {arg}");
			}
		}

		private static void DisableAllChildLights(GrabbableObject item)
		{
			try
			{
				Light[] componentsInChildren = ((Component)item).GetComponentsInChildren<Light>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					((Behaviour)componentsInChildren[i]).enabled = false;
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"DisableAllChildLights failed: {arg}");
			}
		}

		private static object? GetFieldOrPropertyObject(object? instance, string name)
		{
			if (instance == null)
			{
				return null;
			}
			try
			{
				Type type = instance.GetType();
				FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field.GetValue(instance);
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null)
				{
					return property.GetValue(instance);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"GetFieldOrPropertyObject({name}) failed: {arg}");
			}
			return null;
		}

		private static bool GetBoolFieldOrProperty(object? instance, string name)
		{
			if (instance == null)
			{
				return false;
			}
			try
			{
				Type type = instance.GetType();
				FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && field.FieldType == typeof(bool))
				{
					return (bool)field.GetValue(instance);
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.PropertyType == typeof(bool))
				{
					return (bool)property.GetValue(instance);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"GetBoolFieldOrProperty({name}) failed: {arg}");
			}
			return false;
		}

		private static float GetFloatFieldOrProperty(object? instance, string name)
		{
			if (instance == null)
			{
				return 0f;
			}
			try
			{
				Type type = instance.GetType();
				FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					object value = field.GetValue(instance);
					if (value is float result)
					{
						return result;
					}
					if (value is double num)
					{
						return (float)num;
					}
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null)
				{
					object value2 = property.GetValue(instance);
					if (value2 is float result2)
					{
						return result2;
					}
					if (value2 is double)
					{
						double num2 = (double)value2;
						return (float)num2;
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"GetFloatFieldOrProperty({name}) failed: {arg}");
			}
			return 0f;
		}

		private static void SetBoolFieldOrProperty(object instance, string name, bool value)
		{
			try
			{
				Type type = instance.GetType();
				FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && field.FieldType == typeof(bool))
				{
					field.SetValue(instance, value);
					return;
				}
				PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.PropertyType == typeof(bool) && property.CanWrite)
				{
					property.SetValue(instance, value);
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"SetBoolFieldOrProperty({name}) failed: {arg}");
			}
		}
	}
}