Decompiled source of ImmersiveBuildCamera v1.1.1

BepInEx/plugins/ImmersiveBuildCamera/ImmersiveBuildCamera.dll

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

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ImmersiveBuildCamera")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ImmersiveBuildCamera")]
[assembly: AssemblyTitle("ImmersiveBuildCamera")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
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;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 ImmersiveBuildCamera
{
	internal static class BuildCameraDistance
	{
		private const float HeldInputStepsPerSecond = 20f;

		private static bool _initialized;

		internal static float Current { get; private set; }

		internal static void ResetForSession()
		{
			if (!Plugin.RememberScrollDistance.Value || !_initialized)
			{
				Current = Clamp(Plugin.DefaultBuildCameraDistance.Value);
				_initialized = true;
				Plugin.DebugLog($"Camera distance reset to {Current:0.00}.");
			}
		}

		internal static void UpdateFromInput()
		{
			//IL_003a: 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)
			float num = Mathf.Max(0f, Plugin.ScrollDistanceStep.Value);
			if (!(num <= 0f))
			{
				float num2 = num * 20f * Time.unscaledDeltaTime;
				if (Input.GetKey(Plugin.CameraDistanceCloserKey.Value))
				{
					AddDistance(0f - num2);
				}
				if (Input.GetKey(Plugin.CameraDistanceFartherKey.Value))
				{
					AddDistance(num2);
				}
			}
		}

		private static void AddDistance(float delta)
		{
			float num = Clamp(Current + delta);
			if (!Mathf.Approximately(Current, num))
			{
				Current = num;
				Plugin.DebugLog($"Camera distance set to {Current:0.00}.");
			}
		}

		private static float Clamp(float value)
		{
			float num = Mathf.Min(Plugin.MinBuildCameraDistance.Value, Plugin.MaxBuildCameraDistance.Value);
			float num2 = Mathf.Max(Plugin.MinBuildCameraDistance.Value, Plugin.MaxBuildCameraDistance.Value);
			return Mathf.Clamp(value, num, num2);
		}
	}
	internal static class BuildCameraState
	{
		private static int _toggledShoulderDirection;

		private static readonly FieldInfo? RightItemField = AccessTools.Field(typeof(Humanoid), "m_rightItem");

		internal static bool Active { get; private set; }

		internal static bool PrecisionMovementActive { get; private set; }

		internal static bool ShoulderPeekActive => Active && GetShoulderDirection() != 0;

		internal static void Update(Player player)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			if (!CanUseImmersiveCamera(player))
			{
				SetActive(active: false);
				return;
			}
			if (Input.GetKeyDown(Plugin.ToggleCameraKey.Value))
			{
				SetActive(!Active);
			}
			if (Active)
			{
				UpdateShoulderPeekState();
				BuildCameraDistance.UpdateFromInput();
				if (Plugin.EnablePrecisionMovement.Value && Input.GetKeyDown(Plugin.TogglePrecisionMovementKey.Value))
				{
					SetPrecisionMovement(!PrecisionMovementActive);
				}
			}
		}

		internal static void ForceInactive()
		{
			SetActive(active: false);
		}

		internal static int GetShoulderDirection()
		{
			if (!Active)
			{
				return 0;
			}
			if (Plugin.ToggleShoulderPeek.Value)
			{
				return _toggledShoulderDirection;
			}
			return GetHeldShoulderDirection();
		}

		private static void UpdateShoulderPeekState()
		{
			//IL_0020: 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)
			if (!Plugin.ToggleShoulderPeek.Value)
			{
				_toggledShoulderDirection = 0;
				return;
			}
			bool keyDown = Input.GetKeyDown(Plugin.LeftShoulderKey.Value);
			bool keyDown2 = Input.GetKeyDown(Plugin.RightShoulderKey.Value);
			if (keyDown && keyDown2)
			{
				SetShoulderDirection(0);
			}
			else if (keyDown)
			{
				ToggleShoulderDirection(-1);
			}
			else if (keyDown2)
			{
				ToggleShoulderDirection(1);
			}
		}

		private static void ToggleShoulderDirection(int direction)
		{
			if (_toggledShoulderDirection == direction)
			{
				SetShoulderDirection(0);
			}
			else
			{
				SetShoulderDirection(direction);
			}
		}

		private static void SetShoulderDirection(int direction)
		{
			if (_toggledShoulderDirection != direction)
			{
				_toggledShoulderDirection = direction;
				if (direction < 0)
				{
					Plugin.DebugLog("Shoulder peek set to left.");
				}
				else if (direction > 0)
				{
					Plugin.DebugLog("Shoulder peek set to right.");
				}
				else
				{
					Plugin.DebugLog("Shoulder peek centered.");
				}
			}
		}

		private static int GetHeldShoulderDirection()
		{
			//IL_0006: 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)
			bool key = Input.GetKey(Plugin.LeftShoulderKey.Value);
			bool key2 = Input.GetKey(Plugin.RightShoulderKey.Value);
			if (key && !key2)
			{
				return -1;
			}
			if (key2 && !key)
			{
				return 1;
			}
			return 0;
		}

		private static void SetActive(bool active)
		{
			if (Active != active)
			{
				Active = active;
				if (active)
				{
					BuildCameraDistance.ResetForSession();
					PrecisionMovementActive = Plugin.EnablePrecisionMovement.Value && Plugin.PrecisionMovementDefaultOn.Value;
				}
				else
				{
					PrecisionMovementActive = false;
					SetShoulderDirection(0);
					PlayerRendererVisibility.ForceVisible();
				}
				Plugin.Log.LogInfo((object)(active ? ("Immersive build camera active. Precision movement: " + (PrecisionMovementActive ? "on" : "off") + ".") : "Immersive build camera inactive."));
			}
		}

		private static void SetPrecisionMovement(bool active)
		{
			if (PrecisionMovementActive != active)
			{
				PrecisionMovementActive = active;
				Plugin.Log.LogInfo((object)(active ? "Precision movement active." : "Precision movement inactive."));
			}
		}

		private static bool CanUseImmersiveCamera(Player player)
		{
			if (!IsSafePlayerState(player))
			{
				return false;
			}
			if (!HasBuildTool(player))
			{
				return false;
			}
			return true;
		}

		private static bool HasBuildTool(Player player)
		{
			if (RightItemField == null)
			{
				Plugin.Log.LogWarning((object)"Could not find Humanoid.m_rightItem.");
				return false;
			}
			object? value = RightItemField.GetValue(player);
			ItemData val = (ItemData)((value is ItemData) ? value : null);
			if (val == null)
			{
				return false;
			}
			if (val.m_shared == null)
			{
				return false;
			}
			return (Object)(object)val.m_shared.m_buildPieces != (Object)null;
		}

		private static bool IsSafePlayerState(Player player)
		{
			if (((Character)player).IsDead())
			{
				return false;
			}
			if (((Character)player).IsAttached())
			{
				return false;
			}
			if (((Character)player).IsSwimming())
			{
				return false;
			}
			if (InventoryGui.IsVisible())
			{
				return false;
			}
			if (Menu.IsVisible())
			{
				return false;
			}
			if (Minimap.IsOpen())
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(GameCamera))]
	[HarmonyPatch("UpdateCamera")]
	internal static class GameCameraUpdatePatch
	{
		private static readonly FieldInfo? CameraField = AccessTools.Field(typeof(GameCamera), "m_camera");

		private static float _originalFov;

		private static float _originalNearClip;

		private static bool _savedOriginals;

		private static Vector3 _smoothPosition;

		private static Quaternion _smoothRotation = Quaternion.identity;

		private static bool _hasSmoothTransform;

		private static int _cachedCollisionMask = -1;

		private static void Postfix(GameCamera __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			Camera val = GetCamera(__instance) ?? Camera.main;
			if (!((Object)(object)val == (Object)null))
			{
				if (!_savedOriginals)
				{
					_originalFov = val.fieldOfView;
					_originalNearClip = val.nearClipPlane;
					_savedOriginals = true;
				}
				if (!BuildCameraState.Active)
				{
					RestoreCamera(val);
					ResetSmoothing();
				}
				else
				{
					ApplyImmersiveBuildCamera(__instance, val);
				}
			}
		}

		private static Camera? GetCamera(GameCamera gameCamera)
		{
			if (CameraField == null)
			{
				return null;
			}
			object? value = CameraField.GetValue(gameCamera);
			return (Camera?)((value is Camera) ? value : null);
		}

		private static void ApplyImmersiveBuildCamera(GameCamera gameCamera, Camera camera)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0067: 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_0070: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00a7: 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)
			//IL_00b1: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				Transform val = (((Object)(object)((Character)localPlayer).m_eye != (Object)null) ? ((Character)localPlayer).m_eye : ((Component)localPlayer).transform);
				Vector3 position = val.position;
				Vector3 val2 = position;
				Quaternion rotation = val.rotation;
				float num = Mathf.Max(0f, BuildCameraDistance.Current);
				if (num > 0.001f)
				{
					val2 -= val.forward * num;
				}
				int shoulderDirection = BuildCameraState.GetShoulderDirection();
				if (shoulderDirection != 0)
				{
					float num2 = Plugin.ShoulderOffsetX.Value * (float)shoulderDirection;
					val2 += val.right * num2;
					val2 += val.up * Plugin.ShoulderOffsetY.Value;
					val2 -= val.forward * Plugin.ShoulderDistance.Value;
					val2 = ResolveCameraCollision(position, val2);
				}
				else if (num > 0.001f)
				{
					val2 = ResolveCameraCollision(position, val2);
				}
				ApplySmoothedTransform(gameCamera, val2, rotation);
				camera.fieldOfView = Plugin.BuildFov.Value;
				camera.nearClipPlane = Plugin.NearClip.Value;
			}
		}

		private static void ApplySmoothedTransform(GameCamera gameCamera, Vector3 desiredPosition, Quaternion desiredRotation)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_006d: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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_008a: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			if (!_hasSmoothTransform)
			{
				_smoothPosition = ((Component)gameCamera).transform.position;
				_smoothRotation = ((Component)gameCamera).transform.rotation;
				_hasSmoothTransform = true;
			}
			float num = Mathf.Max(0f, Plugin.CameraTransitionSpeed.Value);
			float num2 = ((num <= 0f) ? 1f : (1f - Mathf.Exp((0f - num) * Time.unscaledDeltaTime)));
			_smoothPosition = Vector3.Lerp(_smoothPosition, desiredPosition, num2);
			_smoothRotation = Quaternion.Slerp(_smoothRotation, desiredRotation, num2);
			((Component)gameCamera).transform.position = _smoothPosition;
			((Component)gameCamera).transform.rotation = _smoothRotation;
		}

		private static Vector3 ResolveCameraCollision(Vector3 anchorPosition, Vector3 desiredPosition)
		{
			//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)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = desiredPosition - anchorPosition;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude <= 0.001f)
			{
				return desiredPosition;
			}
			Vector3 val2 = val / magnitude;
			RaycastHit val3 = default(RaycastHit);
			if (!Physics.SphereCast(anchorPosition, Mathf.Max(0.01f, Plugin.CollisionRadius.Value), val2, ref val3, magnitude, GetCollisionMask(), (QueryTriggerInteraction)1))
			{
				return desiredPosition;
			}
			float num = Mathf.Max(0f, ((RaycastHit)(ref val3)).distance - Plugin.CollisionRadius.Value);
			return anchorPosition + val2 * num;
		}

		private static int GetCollisionMask()
		{
			if (_cachedCollisionMask != -1)
			{
				return _cachedCollisionMask;
			}
			int num = LayerMask.GetMask(new string[5] { "Default", "static_solid", "terrain", "piece", "piece_nonsolid" });
			if (num == 0)
			{
				num = -5;
				Plugin.Log.LogWarning((object)"Could not resolve Valheim-specific collision layers. Falling back to Physics.DefaultRaycastLayers.");
			}
			_cachedCollisionMask = num;
			return _cachedCollisionMask;
		}

		private static void RestoreCamera(Camera camera)
		{
			if (_savedOriginals)
			{
				camera.fieldOfView = _originalFov;
				camera.nearClipPlane = _originalNearClip;
			}
		}

		private static void ResetSmoothing()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			_hasSmoothTransform = false;
			_smoothPosition = Vector3.zero;
			_smoothRotation = Quaternion.identity;
		}
	}
	[HarmonyPatch(typeof(Player))]
	[HarmonyPatch("Update")]
	internal static class PlayerUpdatePatch
	{
		private static void Postfix(Player __instance)
		{
			BuildCameraState.Update(__instance);
			PlayerRendererVisibility.Update(__instance);
		}
	}
	internal static class PlayerRendererVisibility
	{
		private static readonly Dictionary<Renderer, bool> OriginalRendererStates = new Dictionary<Renderer, bool>();

		private static readonly List<Renderer> DeadRenderers = new List<Renderer>();

		private static readonly FieldInfo? PlacementGhostField = AccessTools.Field(typeof(Player), "m_placementGhost");

		private static Player? _cachedPlayer;

		private static bool _hidden;

		private static float _nextRefreshTime;

		internal static void Update(Player player)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer))
			{
				bool shouldHide = Plugin.HideLocalPlayerWhenImmersive.Value && BuildCameraState.Active && !BuildCameraState.ShoulderPeekActive;
				Apply(player, shouldHide);
			}
		}

		internal static void ForceVisible()
		{
			RestoreRendererStates();
			ResetCache();
		}

		private static void Apply(Player player, bool shouldHide)
		{
			if ((Object)(object)player == (Object)null)
			{
				ForceVisible();
				return;
			}
			if ((Object)(object)_cachedPlayer != (Object)null && (Object)(object)_cachedPlayer != (Object)(object)player)
			{
				ForceVisible();
			}
			_cachedPlayer = player;
			if (shouldHide)
			{
				HidePlayerRenderers(player);
			}
			else
			{
				RestoreRendererStates();
			}
		}

		private static void HidePlayerRenderers(Player player)
		{
			if (!_hidden)
			{
				OriginalRendererStates.Clear();
				_hidden = true;
				_nextRefreshTime = 0f;
			}
			if (OriginalRendererStates.Count == 0 || Time.unscaledTime >= _nextRefreshTime)
			{
				RefreshRendererCache(player);
				_nextRefreshTime = Time.unscaledTime + 0.25f;
			}
			foreach (Renderer key in OriginalRendererStates.Keys)
			{
				if (!((Object)(object)key == (Object)null) && key.enabled)
				{
					key.enabled = false;
				}
			}
		}

		private static void RefreshRendererCache(Player player)
		{
			RemoveDestroyedRenderers();
			Renderer[] componentsInChildren = ((Component)player).GetComponentsInChildren<Renderer>(true);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				if (!((Object)(object)val == (Object)null) && !ShouldSkipRenderer(player, val) && !OriginalRendererStates.ContainsKey(val))
				{
					OriginalRendererStates.Add(val, val.enabled);
				}
			}
		}

		private static bool ShouldSkipRenderer(Player player, Renderer renderer)
		{
			GameObject placementGhost = GetPlacementGhost(player);
			if ((Object)(object)placementGhost != (Object)null && (Object)(object)((Component)renderer).transform != (Object)null && ((Component)renderer).transform.IsChildOf(placementGhost.transform))
			{
				return true;
			}
			return false;
		}

		private static GameObject? GetPlacementGhost(Player player)
		{
			if (PlacementGhostField == null)
			{
				return null;
			}
			object? value = PlacementGhostField.GetValue(player);
			return (GameObject?)((value is GameObject) ? value : null);
		}

		private static void RestoreRendererStates()
		{
			if (!_hidden && OriginalRendererStates.Count == 0)
			{
				return;
			}
			foreach (KeyValuePair<Renderer, bool> originalRendererState in OriginalRendererStates)
			{
				Renderer key = originalRendererState.Key;
				if (!((Object)(object)key == (Object)null))
				{
					key.enabled = originalRendererState.Value;
				}
			}
			OriginalRendererStates.Clear();
			DeadRenderers.Clear();
			_hidden = false;
			_nextRefreshTime = 0f;
		}

		private static void RemoveDestroyedRenderers()
		{
			DeadRenderers.Clear();
			foreach (Renderer key in OriginalRendererStates.Keys)
			{
				if ((Object)(object)key == (Object)null)
				{
					DeadRenderers.Add(key);
				}
			}
			foreach (Renderer deadRenderer in DeadRenderers)
			{
				OriginalRendererStates.Remove(deadRenderer);
			}
			DeadRenderers.Clear();
		}

		private static void ResetCache()
		{
			_cachedPlayer = null;
			_hidden = false;
			_nextRefreshTime = 0f;
			OriginalRendererStates.Clear();
			DeadRenderers.Clear();
		}
	}
	[BepInPlugin("com.geronimo.valheim.immersivebuildcamera", "Immersive Build Camera", "1.1.0")]
	[BepInProcess("valheim.exe")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.geronimo.valheim.immersivebuildcamera";

		public const string PluginName = "Immersive Build Camera";

		public const string PluginVersion = "1.1.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<KeyCode> ToggleCameraKey;

		internal static ConfigEntry<KeyCode> TogglePrecisionMovementKey;

		internal static ConfigEntry<KeyCode> LeftShoulderKey;

		internal static ConfigEntry<KeyCode> RightShoulderKey;

		internal static ConfigEntry<KeyCode> CameraDistanceCloserKey;

		internal static ConfigEntry<KeyCode> CameraDistanceFartherKey;

		internal static ConfigEntry<float> BuildFov;

		internal static ConfigEntry<float> NearClip;

		internal static ConfigEntry<float> CameraTransitionSpeed;

		internal static ConfigEntry<bool> EnableScrollDistanceAdjust;

		internal static ConfigEntry<float> DefaultBuildCameraDistance;

		internal static ConfigEntry<float> MinBuildCameraDistance;

		internal static ConfigEntry<float> MaxBuildCameraDistance;

		internal static ConfigEntry<float> ScrollDistanceStep;

		internal static ConfigEntry<bool> RememberScrollDistance;

		internal static ConfigEntry<float> ShoulderOffsetX;

		internal static ConfigEntry<float> ShoulderOffsetY;

		internal static ConfigEntry<float> ShoulderDistance;

		internal static ConfigEntry<float> CollisionRadius;

		internal static ConfigEntry<bool> ToggleShoulderPeek;

		internal static ConfigEntry<bool> EnablePrecisionMovement;

		internal static ConfigEntry<bool> PrecisionMovementDefaultOn;

		internal static ConfigEntry<float> PrecisionMoveMultiplier;

		internal static ConfigEntry<bool> HideLocalPlayerWhenImmersive;

		internal static ConfigEntry<bool> EnableDebugLogs;

		private Harmony _harmony = null;

		private void Awake()
		{
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ToggleCameraKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "ToggleCameraKey", (KeyCode)308, "Press this while using a build tool to toggle immersive build camera.");
			TogglePrecisionMovementKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "TogglePrecisionMovementKey", (KeyCode)306, "Press this while immersive build camera is active to toggle slow precision movement.");
			LeftShoulderKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "LeftShoulderKey", (KeyCode)113, "Hold or press this while immersive build camera is active to peek left, depending on ToggleShoulderPeek.");
			RightShoulderKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "RightShoulderKey", (KeyCode)101, "Hold or press this while immersive build camera is active to peek right, depending on ToggleShoulderPeek.");
			CameraDistanceCloserKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "CameraDistanceCloserKey", (KeyCode)280, "Press this while immersive build camera is active to move the camera closer.");
			CameraDistanceFartherKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "CameraDistanceFartherKey", (KeyCode)281, "Press this while immersive build camera is active to move the camera farther away.");
			BuildFov = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "BuildFov", 68f, "Field of view while immersive build camera is active.");
			NearClip = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "NearClip", 0.04f, "Near clipping plane while immersive build camera is active.");
			CameraTransitionSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "CameraTransitionSpeed", 12f, "How quickly the immersive build camera moves toward its target. Set to 0 for instant movement.");
			EnableScrollDistanceAdjust = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera Distance", "EnableScrollDistanceAdjust", false, "Legacy opt-in. If true, mouse wheel also adjusts camera distance, but this can conflict with Valheim build piece rotation.");
			DefaultBuildCameraDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Camera Distance", "DefaultBuildCameraDistance", 0f, "Starting backward camera distance from the player's eye when immersive build camera turns on.");
			MinBuildCameraDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Camera Distance", "MinBuildCameraDistance", 0f, "Closest allowed camera distance.");
			MaxBuildCameraDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Camera Distance", "MaxBuildCameraDistance", 1.25f, "Farthest allowed camera distance.");
			ScrollDistanceStep = ((BaseUnityPlugin)this).Config.Bind<float>("Camera Distance", "ScrollDistanceStep", 0.05f, "Distance changed per camera distance key press or mouse wheel notch.");
			RememberScrollDistance = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera Distance", "RememberScrollDistance", false, "If true, keeps the adjusted camera distance between immersive build camera sessions.");
			ShoulderOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Shoulder Peek", "ShoulderOffsetX", 0.9f, "Horizontal shoulder offset. Higher values make shoulder peek more useful but more likely to hit collision.");
			ShoulderOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Shoulder Peek", "ShoulderOffsetY", 0.06f, "Vertical shoulder offset.");
			ShoulderDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Shoulder Peek", "ShoulderDistance", 0.55f, "Backward shoulder camera distance.");
			CollisionRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Shoulder Peek", "CollisionRadius", 0.1f, "Sphere radius used to prevent shoulder peek camera clipping into objects.");
			ToggleShoulderPeek = ((BaseUnityPlugin)this).Config.Bind<bool>("Shoulder Peek", "ToggleShoulderPeek", false, "If false, shoulder peek keys must be held. If true, shoulder peek keys toggle left, right, or centered.");
			EnablePrecisionMovement = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement", "EnablePrecisionMovement", true, "Allow slow precision movement while immersive build camera is active.");
			PrecisionMovementDefaultOn = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement", "PrecisionMovementDefaultOn", true, "Whether slow precision movement starts enabled whenever immersive build camera is toggled on.");
			PrecisionMoveMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Movement", "PrecisionMoveMultiplier", 0.35f, "Movement input multiplier when precision movement is enabled. Lower means slower.");
			HideLocalPlayerWhenImmersive = ((BaseUnityPlugin)this).Config.Bind<bool>("Local Visibility", "HideLocalPlayerWhenImmersive", true, "Hide only the local player's renderers while immersive build camera is active and shoulder peek is not being used.");
			EnableDebugLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugLogs", false, "Enable extra logging for camera, shoulder peek, precision movement, visibility, and cleanup state changes.");
			_harmony = new Harmony("com.geronimo.valheim.immersivebuildcamera");
			_harmony.PatchAll();
			PrecisionMovementPatches.Apply(_harmony);
			Log.LogInfo((object)"Immersive Build Camera 1.1.0 loaded.");
		}

		internal static void DebugLog(string message)
		{
			ConfigEntry<bool> enableDebugLogs = EnableDebugLogs;
			if (enableDebugLogs != null && enableDebugLogs.Value)
			{
				Log.LogInfo((object)("[Debug] " + message));
			}
		}

		private void OnDestroy()
		{
			BuildCameraState.ForceInactive();
			PlayerRendererVisibility.ForceVisible();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class PrecisionMovementPatches
	{
		internal static void Apply(Harmony harmony)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(Player), "SetControls", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(PrecisionMovementPatches), "PrefixSetControls", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Plugin.Log.LogWarning((object)"Could not find Player.SetControls. Precision movement patch skipped.");
				return;
			}
			if (methodInfo2 == null)
			{
				Plugin.Log.LogWarning((object)"Could not find precision movement prefix.");
				return;
			}
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Plugin.Log.LogInfo((object)"Patched Player.SetControls for precision movement.");
		}

		private static void PrefixSetControls(Player __instance, ref Vector3 movedir, ref bool run, ref bool autoRun)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.EnablePrecisionMovement.Value && BuildCameraState.Active && BuildCameraState.PrecisionMovementActive && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				float num = Mathf.Clamp(Plugin.PrecisionMoveMultiplier.Value, 0.05f, 1f);
				movedir *= num;
				run = false;
				autoRun = false;
			}
		}
	}
}