Decompiled source of Belt Lantern v1.2.1

DarkwaterFlashlight.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("DarkwaterFlashlight")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DarkwaterFlashlight")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f9df4c08-37db-4968-b67e-f54cabf2c0de")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace DarkwaterFlashlight;

[BepInPlugin("egys1n.beltlantern", "Belt Lantern", "1.2.1")]
public class Plugin : BaseUnityPlugin
{
	public const string PluginGUID = "egys1n.beltlantern";

	public const string PluginName = "Belt Lantern";

	public const string PluginVersion = "1.2.1";

	internal static ManualLogSource Log;

	internal static Harmony HarmonyInstance;

	public static ConfigEntry<KeyCode> ToggleKey;

	public static ConfigEntry<KeyCode> SlotKey;

	public static ConfigEntry<float> LightIntensity;

	public static ConfigEntry<float> LightRange;

	public static ConfigEntry<float> OffsetX;

	public static ConfigEntry<float> OffsetY;

	public static ConfigEntry<float> OffsetZ;

	internal static FlashlightSlotController SlotController;

	private void Awake()
	{
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Expected O, but got Unknown
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "ToggleLight", (KeyCode)108, "Toggle the belt lantern ON / OFF");
		SlotKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "MoveToSlot", (KeyCode)118, "Move lantern between hand and belt slot");
		LightIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Light", "IntensityValue", 2.7f, "Point light intensity (higher = brighter). Default 2.7");
		LightRange = ((BaseUnityPlugin)this).Config.Bind<float>("Light", "Range", 12f, "Point light radius in metres. Default 12");
		OffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Position", "OffsetX", 0.2f, "Left/Right offset from head bone");
		OffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Position", "OffsetY", -0.7f, "Up/Down offset (negative = lower, belt level)");
		OffsetZ = ((BaseUnityPlugin)this).Config.Bind<float>("Position", "OffsetZ", 0.1f, "Forward/Back offset");
		HarmonyInstance = new Harmony("egys1n.beltlantern");
		HarmonyInstance.PatchAll();
		Log.LogInfo((object)"Belt Lantern v1.2.1 loaded.");
		Log.LogInfo((object)$"  Toggle: [{ToggleKey.Value}]  |  Slot transfer: [{SlotKey.Value}]");
	}

	private void Update()
	{
		if ((Object)(object)SlotController == (Object)null)
		{
			TryAttachController();
		}
		else
		{
			SlotController.ProcessInput();
		}
	}

	private void TryAttachController()
	{
		C_Controller_Player[] array = Object.FindObjectsByType<C_Controller_Player>((FindObjectsSortMode)0);
		foreach (C_Controller_Player val in array)
		{
			if (!((Object)(object)((C_Controller)val).E_Inventory() == (Object)null))
			{
				FlashlightSlotController component = ((Component)val).GetComponent<FlashlightSlotController>();
				if ((Object)(object)component != (Object)null)
				{
					SlotController = component;
					break;
				}
				SlotController = ((Component)val).gameObject.AddComponent<FlashlightSlotController>();
				SlotController.Initialize(val);
				Log.LogInfo((object)"FlashlightSlotController attached to local player.");
				break;
			}
		}
	}

	private void OnDestroy()
	{
		Harmony harmonyInstance = HarmonyInstance;
		if (harmonyInstance != null)
		{
			harmonyInstance.UnpatchSelf();
		}
	}
}
public class FlashlightSlotController : MonoBehaviour
{
	public enum SlotState
	{
		Empty,
		OccupiedOff,
		OccupiedOn
	}

	[CompilerGenerated]
	private sealed class <AtmosphericFlicker>d__46 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public FlashlightSlotController <>4__this;

		private float <dipTarget>5__2;

		private float <dipDuration>5__3;

		private float <elapsed>5__4;

		private float <startIntensity>5__5;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <AtmosphericFlicker>d__46(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			int num = <>1__state;
			FlashlightSlotController flashlightSlotController = <>4__this;
			switch (num)
			{
			default:
				return false;
			case 0:
			{
				<>1__state = -1;
				flashlightSlotController.flickerRunning = true;
				float num2 = Random.Range(0.2f, 0.4f);
				<dipTarget>5__2 = flashlightSlotController.targetIntensity * (1f - num2);
				<dipDuration>5__3 = Random.Range(0.1f, 0.3f);
				<elapsed>5__4 = 0f;
				<startIntensity>5__5 = flashlightSlotController.beltLight.intensity;
				goto IL_00d9;
			}
			case 1:
				<>1__state = -1;
				goto IL_00d9;
			case 2:
				{
					<>1__state = -1;
					flashlightSlotController.beltLight.intensity = flashlightSlotController.targetIntensity;
					flashlightSlotController.flickerRunning = false;
					return false;
				}
				IL_00d9:
				if (<elapsed>5__4 < <dipDuration>5__3)
				{
					<elapsed>5__4 += Time.deltaTime;
					flashlightSlotController.beltLight.intensity = Mathf.Lerp(<startIntensity>5__5, <dipTarget>5__2, <elapsed>5__4 / <dipDuration>5__3);
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				<>2__current = (object)new WaitForSeconds(0.04f);
				<>1__state = 2;
				return true;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <Co_NetworkSync>d__57 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public FlashlightSlotController <>4__this;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <Co_NetworkSync>d__57(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			int num = <>1__state;
			FlashlightSlotController flashlightSlotController = <>4__this;
			if (num != 0)
			{
				if (num != 1)
				{
					return false;
				}
				<>1__state = -1;
				C_Controller_Player[] array = Object.FindObjectsByType<C_Controller_Player>((FindObjectsSortMode)0);
				foreach (C_Controller_Player val in array)
				{
					if (!((Object)(object)val == (Object)(object)flashlightSlotController.playerController))
					{
						flashlightSlotController.ReconcileRemotePlayer(val);
					}
				}
			}
			else
			{
				<>1__state = -1;
			}
			<>2__current = (object)new WaitForSeconds(5f);
			<>1__state = 1;
			return true;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <LoadAudioClip>d__33 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public FlashlightSlotController <>4__this;

		private UnityWebRequest <www>5__2;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <LoadAudioClip>d__33(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			int num = <>1__state;
			if (num == -3 || num == 1)
			{
				try
				{
				}
				finally
				{
					<>m__Finally1();
				}
			}
			<www>5__2 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Invalid comparison between Unknown and I4
			try
			{
				int num = <>1__state;
				FlashlightSlotController flashlightSlotController = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					string text = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location), "SFX_Lantern_Belt_Action.wav");
					if (!File.Exists(text))
					{
						Plugin.Log.LogWarning((object)("[SFX] Sound file not found at: " + text + ". Audio will be disabled."));
						return false;
					}
					string text2 = "file://" + text;
					<www>5__2 = UnityWebRequestMultimedia.GetAudioClip(text2, (AudioType)20);
					<>1__state = -3;
					<>2__current = <www>5__2.SendWebRequest();
					<>1__state = 1;
					return true;
				}
				case 1:
					<>1__state = -3;
					if ((int)<www>5__2.result == 1)
					{
						_sfxAction = DownloadHandlerAudioClip.GetContent(<www>5__2);
						flashlightSlotController._isAudioLoaded = true;
						Plugin.Log.LogInfo((object)"SFX_Lantern_Belt_Action.wav loaded successfully.");
					}
					else
					{
						Plugin.Log.LogError((object)("[SFX] Failed to load: " + <www>5__2.error));
					}
					<>m__Finally1();
					<www>5__2 = null;
					return false;
				}
			}
			catch
			{
				//try-fault
				((IDisposable)this).Dispose();
				throw;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		private void <>m__Finally1()
		{
			<>1__state = -1;
			if (<www>5__2 != null)
			{
				((IDisposable)<www>5__2).Dispose();
			}
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	private C_Controller_Player playerController;

	private E_Inventory playerInventory;

	private Light beltLight;

	private GameObject beltLightObject;

	private PlayerItem storedLanternItem;

	private static AudioClip _sfxAction;

	private AudioSource _audioSource;

	private bool _isAudioLoaded;

	private bool _showSettings;

	private float _settingR = 0.8f;

	private float _settingG = 0.62f;

	private float _settingB = 0.42f;

	private float _settingIntensity = 2.7f;

	private Rect _settingWinRect = new Rect(60f, 60f, 340f, 260f);

	private bool inputCooldown;

	private float cooldownTimer;

	private const float INPUT_COOLDOWN = 0.3f;

	private float flickerTimer;

	private bool flickerRunning;

	private float targetIntensity = 2.7f;

	private Texture2D hudIconTexture;

	private const int HUD_ICON_SIZE = 42;

	private const int HUD_MARGIN = 8;

	private RectTransform _inventoryBarRect;

	private float _findBarCooldown;

	internal static bool NetworkSyncState;

	internal static bool NetworkSyncDirty;

	public SlotState CurrentState { get; private set; }

	public void Initialize(C_Controller_Player player)
	{
		playerController = player;
		playerInventory = ((C_Controller)player).E_Inventory();
		CreateBeltLight();
		CreateHUDIcon();
		ScheduleNextFlicker();
		FindInventoryBar();
		((MonoBehaviour)this).StartCoroutine(Co_NetworkSync());
		InitializeAudio();
		Plugin.Log.LogInfo((object)"Belt Lantern Mod initialized.");
	}

	private void CreateBeltLight()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		beltLightObject = new GameObject("BeltLanternLight");
		Transform val = (((Object)(object)playerController.headJoint != (Object)null) ? playerController.headJoint : ((Component)playerController).transform);
		beltLightObject.transform.SetParent(val, false);
		beltLightObject.transform.localPosition = new Vector3(Plugin.OffsetX.Value, Plugin.OffsetY.Value, Plugin.OffsetZ.Value);
		beltLightObject.transform.localRotation = Quaternion.identity;
		beltLight = beltLightObject.AddComponent<Light>();
		beltLight.type = (LightType)2;
		beltLight.color = new Color(0.8f, 0.62f, 0.42f);
		beltLight.intensity = Plugin.LightIntensity.Value;
		beltLight.range = Plugin.LightRange.Value;
		beltLight.shadows = (LightShadows)2;
		beltLight.shadowStrength = 0.4f;
		beltLight.renderMode = (LightRenderMode)1;
		targetIntensity = Plugin.LightIntensity.Value;
		beltLightObject.SetActive(false);
		Plugin.Log.LogInfo((object)"Belt lantern Point Light created.");
	}

	private void InitializeAudio()
	{
		_audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
		_audioSource.playOnAwake = false;
		_audioSource.spatialBlend = 1f;
		_audioSource.volume = 0.7f;
		((MonoBehaviour)this).StartCoroutine(LoadAudioClip());
	}

	[IteratorStateMachine(typeof(<LoadAudioClip>d__33))]
	private IEnumerator LoadAudioClip()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <LoadAudioClip>d__33(0)
		{
			<>4__this = this
		};
	}

	private void PlayActionSFX()
	{
		if (_isAudioLoaded && (Object)(object)_sfxAction != (Object)null && (Object)(object)_audioSource != (Object)null)
		{
			_audioSource.PlayOneShot(_sfxAction);
		}
	}

	private void CreateHUDIcon()
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Expected O, but got Unknown
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0185: Unknown result type (might be due to invalid IL or missing references)
		//IL_019a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		hudIconTexture = new Texture2D(42, 42, (TextureFormat)4, false);
		Color val = default(Color);
		((Color)(ref val))..ctor(0f, 0f, 0f, 0f);
		Color col = default(Color);
		((Color)(ref col))..ctor(1f, 0.85f, 0.3f, 1f);
		new Color(1f, 0.8f, 0.2f, 0.3f);
		for (int i = 0; i < 42; i++)
		{
			for (int j = 0; j < 42; j++)
			{
				hudIconTexture.SetPixel(i, j, val);
			}
		}
		int num = 21;
		int num2 = 21;
		for (int k = 0; k < 42; k++)
		{
			for (int l = 0; l < 42; l++)
			{
				float num3 = Vector2.Distance(new Vector2((float)k, (float)l), new Vector2((float)num, (float)num2));
				if (num3 < 18f)
				{
					float num4 = Mathf.Lerp(0.4f, 0f, num3 / 18f);
					hudIconTexture.SetPixel(k, l, new Color(1f, 0.8f, 0.2f, num4));
				}
			}
		}
		DrawFilledRect(hudIconTexture, num - 6, num2 - 7, 12, 14, col);
		DrawFilledRect(hudIconTexture, num - 4, num2 - 5, 8, 10, new Color(1f, 1f, 1f, 0.8f));
		DrawFilledRect(hudIconTexture, num - 7, num2 + 7, 14, 3, col);
		DrawFilledRect(hudIconTexture, num - 8, num2 - 10, 16, 3, col);
		DrawFilledRect(hudIconTexture, num - 1, num2 + 10, 3, 5, col);
		hudIconTexture.Apply();
	}

	private static void DrawFilledRect(Texture2D tex, int x0, int y0, int w, int h, Color col)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		for (int i = x0; i < x0 + w && i < ((Texture)tex).width; i++)
		{
			for (int j = y0; j < y0 + h && j < ((Texture)tex).height; j++)
			{
				if (i >= 0 && j >= 0)
				{
					tex.SetPixel(i, j, col);
				}
			}
		}
	}

	private void OnGUI()
	{
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		if (CurrentState == SlotState.Empty || (Object)(object)hudIconTexture == (Object)null)
		{
			return;
		}
		if ((Object)(object)_inventoryBarRect == (Object)null)
		{
			_findBarCooldown -= Time.deltaTime;
			if (_findBarCooldown <= 0f)
			{
				FindInventoryBar();
				_findBarCooldown = 2f;
			}
		}
		float num = ((CurrentState == SlotState.OccupiedOn) ? 1f : 0.4f);
		GUI.color = new Color(1f, 1f, 1f, num);
		float num2;
		float num3;
		if ((Object)(object)_inventoryBarRect != (Object)null)
		{
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			_inventoryBarRect.GetWorldCorners(array);
			float x = array[0].x;
			float y = array[0].y;
			num2 = x - 42f - 8f;
			num3 = (float)Screen.height - y - 42f;
		}
		else
		{
			num2 = (float)Screen.width * 0.5f - (float)Screen.width * 0.22f - 42f;
			num3 = (float)Screen.height * 0.88f - 42f;
		}
		GUI.DrawTexture(new Rect(num2, num3, 42f, 42f), (Texture)(object)hudIconTexture);
		GUI.color = Color.white;
		if (_showSettings)
		{
			DrawSettingsWindow();
		}
	}

	private void DrawSettingsWindow()
	{
		//IL_0007: 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_0022: Expected O, but got Unknown
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		_settingWinRect = GUI.Window(9823, _settingWinRect, new WindowFunction(SettingsWindowContent), "Belt Lantern — Настройка");
	}

	private void SettingsWindowContent(int id)
	{
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_026e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		//IL_0297: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0323: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)beltLight == (Object)null)
		{
			GUI.Label(new Rect(10f, 30f, 320f, 20f), "Лампа не активна.");
			return;
		}
		float num = 28f;
		float num2 = 100f;
		float num3 = 210f;
		GUI.Label(new Rect(10f, num, num2, 20f), $"Яркость: {_settingIntensity:F1}");
		float num4 = GUI.HorizontalSlider(new Rect(120f, num + 4f, num3, 16f), _settingIntensity, 0.5f, 10f);
		if (Mathf.Abs(num4 - _settingIntensity) > 0.01f)
		{
			_settingIntensity = num4;
			beltLight.intensity = _settingIntensity;
			targetIntensity = _settingIntensity;
		}
		num += 30f;
		GUI.Label(new Rect(10f, num, num2, 20f), $"Красный: {_settingR:F2}");
		float num5 = GUI.HorizontalSlider(new Rect(120f, num + 4f, num3, 16f), _settingR, 0.5f, 1f);
		if (Mathf.Abs(num5 - _settingR) > 0.001f)
		{
			_settingR = num5;
			ApplyColor();
		}
		num += 30f;
		GUI.Label(new Rect(10f, num, num2, 20f), $"Зелёный: {_settingG:F2}");
		float num6 = GUI.HorizontalSlider(new Rect(120f, num + 4f, num3, 16f), _settingG, 0.4f, 1f);
		if (Mathf.Abs(num6 - _settingG) > 0.001f)
		{
			_settingG = num6;
			ApplyColor();
		}
		num += 30f;
		GUI.Label(new Rect(10f, num, num2, 20f), $"Синий: {_settingB:F2}");
		float num7 = GUI.HorizontalSlider(new Rect(120f, num + 4f, num3, 16f), _settingB, 0.1f, 1f);
		if (Mathf.Abs(num7 - _settingB) > 0.001f)
		{
			_settingB = num7;
			ApplyColor();
		}
		num += 30f;
		GUI.color = new Color(_settingR, _settingG, _settingB);
		GUI.DrawTexture(new Rect(10f, num, 320f, 24f), (Texture)(object)Texture2D.whiteTexture);
		GUI.color = Color.white;
		num += 32f;
		GUI.Label(new Rect(10f, num, 320f, 20f), $"new Color({_settingR:F2}f, {_settingG:F2}f, {_settingB:F2}f)  intensity={_settingIntensity:F1}f");
		num += 28f;
		if (GUI.Button(new Rect(10f, num, 320f, 26f), "Закрыть (Alt+V)"))
		{
			_showSettings = false;
		}
		GUI.DragWindow();
	}

	private void ApplyColor()
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)beltLight != (Object)null)
		{
			beltLight.color = new Color(_settingR, _settingG, _settingB);
		}
	}

	private void FindInventoryBar()
	{
		GameObject val = GameObject.Find("PlayerUI");
		if ((Object)(object)val == (Object)null)
		{
			Plugin.Log.LogWarning((object)"[HUD] PlayerUI not found yet — will retry.");
			return;
		}
		_inventoryBarRect = val.GetComponent<RectTransform>();
		Plugin.Log.LogInfo((object)("[HUD] Bound to " + ((Object)val).name + " (RectTransform found)."));
		RectTransform val2 = FindChildWithKeyword(val.transform, new string[5] { "inventory", "item", "slot", "hotbar", "equip" });
		if ((Object)(object)val2 != (Object)null)
		{
			_inventoryBarRect = val2;
			Plugin.Log.LogInfo((object)("[HUD] Refined binding to deeper child: " + ((Object)val2).name));
		}
	}

	private RectTransform FindChildWithKeyword(Transform parent, string[] keywords)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		foreach (Transform item in parent)
		{
			Transform val = item;
			string text = ((Object)val).name.ToLower();
			foreach (string value in keywords)
			{
				if (text.Contains(value))
				{
					return ((Component)val).GetComponent<RectTransform>();
				}
			}
			RectTransform val2 = FindChildWithKeyword(val, keywords);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2;
			}
		}
		return null;
	}

	public void ProcessInput()
	{
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)playerInventory == (Object)null || (Object)(object)playerController == (Object)null)
		{
			return;
		}
		if (inputCooldown)
		{
			cooldownTimer -= Time.deltaTime;
			if (!(cooldownTimer <= 0f))
			{
				return;
			}
			inputCooldown = false;
		}
		if (IsPlayerBusy())
		{
			return;
		}
		if (CurrentState == SlotState.OccupiedOn)
		{
			TickFlicker();
		}
		bool flag = Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307);
		if (flag && Input.GetKeyDown((KeyCode)118))
		{
			_showSettings = !_showSettings;
			if (_showSettings && (Object)(object)beltLight != (Object)null)
			{
				_settingR = beltLight.color.r;
				_settingG = beltLight.color.g;
				_settingB = beltLight.color.b;
				_settingIntensity = beltLight.intensity;
			}
			StartCooldown();
		}
		else
		{
			if (Input.GetKeyDown(Plugin.ToggleKey.Value))
			{
				HandleToggleLight();
				StartCooldown();
			}
			if (!flag && Input.GetKeyDown(Plugin.SlotKey.Value))
			{
				HandleSlotTransfer();
				StartCooldown();
			}
		}
	}

	private void ScheduleNextFlicker()
	{
		flickerTimer = Random.Range(30f, 120f);
	}

	private void TickFlicker()
	{
		flickerTimer -= Time.deltaTime;
		if (flickerTimer <= 0f && !flickerRunning)
		{
			((MonoBehaviour)this).StartCoroutine(AtmosphericFlicker());
			ScheduleNextFlicker();
		}
	}

	[IteratorStateMachine(typeof(<AtmosphericFlicker>d__46))]
	private IEnumerator AtmosphericFlicker()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <AtmosphericFlicker>d__46(0)
		{
			<>4__this = this
		};
	}

	private void HandleToggleLight()
	{
		switch (CurrentState)
		{
		case SlotState.OccupiedOff:
			beltLightObject.SetActive(true);
			CurrentState = SlotState.OccupiedOn;
			BroadcastLightState(on: true);
			PlayActionSFX();
			Plugin.Log.LogInfo((object)"Belt lantern ON.");
			break;
		case SlotState.OccupiedOn:
			beltLightObject.SetActive(false);
			CurrentState = SlotState.OccupiedOff;
			BroadcastLightState(on: false);
			PlayActionSFX();
			Plugin.Log.LogInfo((object)"Belt lantern OFF.");
			break;
		case SlotState.Empty:
			break;
		}
	}

	private void BroadcastLightState(bool on)
	{
		NetworkSyncState = on;
		NetworkSyncDirty = true;
		DispatchNetworkState(on);
		Plugin.Log.LogInfo((object)$"[NET] Broadcasting belt lamp state = {on}");
	}

	public static void ApplyRemoteLightState(C_Controller_Player remotePlayer, bool on)
	{
		BeltLanternRemoteMirror beltLanternRemoteMirror = ((Component)remotePlayer).GetComponent<BeltLanternRemoteMirror>();
		if ((Object)(object)beltLanternRemoteMirror == (Object)null)
		{
			beltLanternRemoteMirror = ((Component)remotePlayer).gameObject.AddComponent<BeltLanternRemoteMirror>();
		}
		beltLanternRemoteMirror.SetState(on);
	}

	private void HandleSlotTransfer()
	{
		if ((Object)(object)playerInventory == (Object)null)
		{
			return;
		}
		if (playerInventory.HoldingLantern())
		{
			if (CurrentState != 0)
			{
				Plugin.Log.LogInfo((object)"Belt slot already occupied!");
			}
			else
			{
				MoveFromHandToSlot();
			}
		}
		else if (CurrentState == SlotState.OccupiedOff || CurrentState == SlotState.OccupiedOn)
		{
			if (playerInventory.currentlyEquippedItem != null)
			{
				Plugin.Log.LogInfo((object)"Hands busy — unequip current item first.");
			}
			else
			{
				MoveFromSlotToHand();
			}
		}
		else
		{
			Plugin.Log.LogInfo((object)"No lantern to move. Equip a lantern, then press V.");
		}
	}

	private void MoveFromHandToSlot()
	{
		storedLanternItem = playerInventory.currentlyEquippedItem.DeepCopy();
		int num = -1;
		for (int i = 0; i < playerInventory.inventoryItems.Length; i++)
		{
			if (playerInventory.inventoryItems[i] != null && playerInventory.inventoryItems[i].GetHash() == storedLanternItem.GetHash())
			{
				num = i;
				break;
			}
		}
		playerInventory.UnequipCurrentItem(false);
		if (num >= 0)
		{
			playerInventory.DestroyItem(storedLanternItem.GetHash(), 1, num);
		}
		CurrentState = SlotState.OccupiedOff;
		Plugin.Log.LogInfo((object)("Lantern → belt slot. (" + storedLanternItem.itemData.name + ")"));
	}

	private void MoveFromSlotToHand()
	{
		if (storedLanternItem == null)
		{
			Plugin.Log.LogWarning((object)"No stored lantern data to restore!");
			CurrentState = SlotState.Empty;
			return;
		}
		if (CurrentState == SlotState.OccupiedOn)
		{
			beltLightObject.SetActive(false);
			BroadcastLightState(on: false);
		}
		if (!playerInventory.AddItem(storedLanternItem.DeepCopy(), false))
		{
			Plugin.Log.LogInfo((object)"Inventory full! Cannot retrieve lantern.");
			if (CurrentState == SlotState.OccupiedOn)
			{
				beltLightObject.SetActive(true);
				BroadcastLightState(on: true);
			}
		}
		else
		{
			storedLanternItem = null;
			CurrentState = SlotState.Empty;
			Plugin.Log.LogInfo((object)"Lantern ← belt slot returned to inventory.");
		}
	}

	public void OnPlayerDeath()
	{
		if (CurrentState != 0)
		{
			Plugin.Log.LogInfo((object)"Player died — dropping belt lantern.");
			beltLightObject.SetActive(false);
			BroadcastLightState(on: false);
			if (storedLanternItem != null)
			{
				playerInventory.DropItem(storedLanternItem, 1);
				storedLanternItem = null;
			}
			CurrentState = SlotState.Empty;
		}
	}

	private bool IsPlayerBusy()
	{
		if (playerController.UsingTerminal())
		{
			return true;
		}
		if (playerInventory.lockInventory)
		{
			return true;
		}
		E_HealthController component = ((Component)playerController).GetComponent<E_HealthController>();
		if ((Object)(object)component != (Object)null && component.dead)
		{
			return true;
		}
		return false;
	}

	[IteratorStateMachine(typeof(<Co_NetworkSync>d__57))]
	private IEnumerator Co_NetworkSync()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <Co_NetworkSync>d__57(0)
		{
			<>4__this = this
		};
	}

	private void ReconcileRemotePlayer(C_Controller_Player remotePlayer)
	{
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			E_Inventory val = ((C_Controller)remotePlayer).E_Inventory();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			bool flag = false;
			bool flag2 = false;
			PlayerItem currentlyEquippedItem = val.currentlyEquippedItem;
			if (currentlyEquippedItem != null && IsLantern(currentlyEquippedItem))
			{
				flag2 = true;
			}
			foreach (Transform item in ((Component)val).transform)
			{
				PlayerItem component = ((Component)item).GetComponent<PlayerItem>();
				if (component != null && IsLantern(component))
				{
					flag = true;
					break;
				}
			}
			bool on = flag && !flag2;
			ApplyRemoteLightState(remotePlayer, on);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Sync error for player " + ((Object)remotePlayer).name + ": " + ex.Message));
		}
	}

	public void DispatchNetworkState(bool on)
	{
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Type type = AccessTools.TypeByName("E_ChatController");
			if (type == null)
			{
				return;
			}
			Object val = Object.FindFirstObjectByType(type);
			if (!(val == (Object)null))
			{
				string name = ((Object)((Component)playerController).gameObject).name;
				string text = (on ? "1" : "0");
				string text2 = "/BELT_SYNC:" + name + ":" + text;
				MethodInfo methodInfo = AccessTools.Method(type, "AddMessage", new Type[3]
				{
					typeof(string),
					typeof(string),
					typeof(Color)
				}, (Type[])null);
				if (methodInfo != null)
				{
					methodInfo.Invoke(val, new object[3]
					{
						text2,
						name,
						Color.black
					});
				}
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("[Net] Dispatch error: " + ex.Message));
		}
	}

	private bool IsLantern(PlayerItem item)
	{
		if (item == null || item.itemData == null)
		{
			return false;
		}
		if (!item.itemData.name.ToLower().Contains("lantern"))
		{
			return item.itemData.name.ToLower().Contains("flashlight");
		}
		return true;
	}

	private void StartCooldown()
	{
		inputCooldown = true;
		cooldownTimer = 0.3f;
	}

	private void OnDestroy()
	{
		if ((Object)(object)beltLightObject != (Object)null)
		{
			Object.Destroy((Object)(object)beltLightObject);
		}
		if ((Object)(object)hudIconTexture != (Object)null)
		{
			Object.Destroy((Object)(object)hudIconTexture);
		}
	}
}
public static class FlashlightSlotPatches
{
	[HarmonyPatch(typeof(E_HealthController), "KillPlayer")]
	[HarmonyPostfix]
	public static void KillPlayer_Postfix(E_HealthController __instance)
	{
		if (!((Object)(object)Plugin.SlotController == (Object)null) && !((Object)/*isinst with value type is only supported in some contexts*/ == (Object)null))
		{
			Plugin.Log.LogInfo((object)"[Patch] KillPlayer — dropping belt lantern.");
			Plugin.SlotController.OnPlayerDeath();
		}
	}

	[HarmonyPatch(typeof(E_Inventory), "DropAllItems")]
	[HarmonyPostfix]
	public static void DropAllItems_Postfix(E_Inventory __instance)
	{
		if (!((Object)(object)Plugin.SlotController == (Object)null))
		{
			Plugin.Log.LogInfo((object)"[Patch] DropAllItems — clearing belt slot.");
			Plugin.SlotController.OnPlayerDeath();
		}
	}

	[HarmonyPatch(typeof(C_Controller_Player), "RPC_EquipItem")]
	[HarmonyPostfix]
	public static void RPC_EquipItem_Postfix(C_Controller_Player __instance, int P_itemID, bool P_override)
	{
		if (FlashlightSlotController.NetworkSyncDirty)
		{
			FlashlightSlotController.NetworkSyncDirty = false;
		}
		if ((!((Object)(object)Plugin.SlotController != (Object)null) || !((Object)(object)__instance == (Object)(object)((Component)Plugin.SlotController).GetComponent<C_Controller_Player>())) && !((Object)(object)Plugin.SlotController == (Object)null))
		{
			FlashlightSlotController.ApplyRemoteLightState(__instance, FlashlightSlotController.NetworkSyncState);
		}
	}

	[HarmonyPatch("E_ChatController", "AddMessage")]
	[HarmonyPrefix]
	public static bool AddMessage_Prefix(string P_message, string P_user, Color P_color)
	{
		if (string.IsNullOrEmpty(P_message))
		{
			return true;
		}
		if (P_message.StartsWith("/BELT_SYNC"))
		{
			Plugin.Log.LogInfo((object)("[Net] Intercepted mod packet: " + P_message));
			try
			{
				string[] array = P_message.Split(new char[1] { ':' });
				if (array.Length >= 3)
				{
					string text = array[1];
					bool on = array[2] == "1";
					C_Controller_Player[] array2 = Object.FindObjectsByType<C_Controller_Player>((FindObjectsSortMode)0);
					foreach (C_Controller_Player val in array2)
					{
						if (((Object)((Component)val).gameObject).name == text)
						{
							FlashlightSlotController.ApplyRemoteLightState(val, on);
							break;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[Net] Intercept parse error: " + ex.Message));
			}
			return false;
		}
		return true;
	}
}
public class BeltLanternRemoteMirror : MonoBehaviour
{
	private Light mirrorLight;

	private GameObject mirrorLightObject;

	private bool isOn;

	private void Awake()
	{
		CreateMirrorLight();
	}

	private void CreateMirrorLight()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		mirrorLightObject = new GameObject("BeltLanternMirror");
		Transform val = null;
		C_Controller_Player component = ((Component)this).GetComponent<C_Controller_Player>();
		val = ((!((Object)(object)component != (Object)null) || !((Object)(object)component.headJoint != (Object)null)) ? ((Component)this).transform : component.headJoint);
		mirrorLightObject.transform.SetParent(val, false);
		mirrorLightObject.transform.localPosition = new Vector3(Plugin.OffsetX.Value, Plugin.OffsetY.Value, Plugin.OffsetZ.Value);
		mirrorLightObject.transform.localRotation = Quaternion.identity;
		mirrorLight = mirrorLightObject.AddComponent<Light>();
		mirrorLight.type = (LightType)2;
		mirrorLight.color = new Color(1f, 0.7f, 0.28f);
		mirrorLight.intensity = Plugin.LightIntensity.Value;
		mirrorLight.range = Plugin.LightRange.Value;
		mirrorLight.shadows = (LightShadows)0;
		mirrorLight.renderMode = (LightRenderMode)0;
		mirrorLightObject.SetActive(false);
	}

	public void SetState(bool on)
	{
		isOn = on;
		if ((Object)(object)mirrorLightObject != (Object)null)
		{
			mirrorLightObject.SetActive(on);
		}
	}

	private void OnDestroy()
	{
		if ((Object)(object)mirrorLightObject != (Object)null)
		{
			Object.Destroy((Object)(object)mirrorLightObject);
		}
	}
}