Decompiled source of Shack Magic Cam v1.0.0

ShackMagicCam.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TMPro;
using TheShack.MagicCam.Compatibility.WardIsLove;
using UnityEngine;
using UnityEngine.UI;

[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("ShackMagicCam")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("GPL-3.0. Portions copyright Cartur (jekkle), Azumatt and gittywithexcitement.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Shack Magic Cam")]
[assembly: AssemblyTitle("ShackMagicCam")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 TheShack.MagicCam
{
	internal static class Access
	{
		private static readonly FieldRef<Humanoid, ItemData> RightItemRef = AccessTools.FieldRefAccess<Humanoid, ItemData>("m_rightItem");

		private static readonly FieldRef<Humanoid, ItemData> LeftItemRef = AccessTools.FieldRefAccess<Humanoid, ItemData>("m_leftItem");

		private static readonly FieldRef<Humanoid, ItemData> HelmetItemRef = AccessTools.FieldRefAccess<Humanoid, ItemData>("m_helmetItem");

		private static readonly FieldRef<Humanoid, VisEquipment> VisEquipmentRef = AccessTools.FieldRefAccess<Humanoid, VisEquipment>("m_visEquipment");

		private static readonly FieldRef<VisEquipment, GameObject> HelmetItemInstanceRef = AccessTools.FieldRefAccess<VisEquipment, GameObject>("m_helmetItemInstance");

		private static readonly FieldRef<Player, int> AutoPickupMaskRef = AccessTools.FieldRefAccess<Player, int>("m_autoPickupMask");

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

		private static readonly FieldRef<GameCamera, float> CameraDistanceRef = AccessTools.FieldRefAccess<GameCamera, float>("m_distance");

		private static readonly FieldRef<SE_Demister, GameObject> BallInstanceRef = AccessTools.FieldRefAccess<SE_Demister, GameObject>("m_ballInstance");

		private static readonly FieldRef<SE_Demister, Vector3> BallVelocityRef = AccessTools.FieldRefAccess<SE_Demister, Vector3>("m_ballVel");

		private static readonly FieldRef<SE_Demister, int> CoverRayMaskRef = AccessTools.FieldRefAccess<SE_Demister, int>("m_coverRayMask");

		private static readonly FieldRef<StatusEffect, float> StatusTimeRef = AccessTools.FieldRefAccess<StatusEffect, float>("m_time");

		private static readonly FieldRef<StatusEffect, float> StatusMessageTimerRef = AccessTools.FieldRefAccess<StatusEffect, float>("m_msgTimer");

		private static readonly FieldRef<bool> EnableAutoPickupRef = AccessTools.StaticFieldRefAccess<bool>(AccessTools.Field(typeof(Player), "m_enableAutoPickup"));

		private static readonly FieldRef<float> TakeInputDelayRef = AccessTools.StaticFieldRefAccess<float>(AccessTools.Field(typeof(Character), "takeInputDelay"));

		private static readonly FieldRef<List<CraftingStation>> AllStationsRef = AccessTools.StaticFieldRefAccess<List<CraftingStation>>(AccessTools.Field(typeof(CraftingStation), "m_allStations"));

		private static readonly Func<Character, bool> TakeInputCall = AccessTools.MethodDelegate<Func<Character, bool>>(AccessTools.Method(typeof(Character), "TakeInput", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Action<Player, bool, float> UpdatePlacementCall = AccessTools.MethodDelegate<Action<Player, bool, float>>(AccessTools.Method(typeof(Player), "UpdatePlacement", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Action<Localization, string, string> AddWordCall = AccessTools.MethodDelegate<Action<Localization, string, string>>(AccessTools.Method(typeof(Localization), "AddWord", (Type[])null, (Type[])null), (object)null, true);

		internal static bool EnableAutoPickup => EnableAutoPickupRef.Invoke();

		internal static ref float TakeInputDelay => ref TakeInputDelayRef.Invoke();

		internal static List<CraftingStation> AllStations => AllStationsRef.Invoke();

		internal static ItemData RightItem(Humanoid humanoid)
		{
			return RightItemRef.Invoke(humanoid);
		}

		internal static ItemData LeftItem(Humanoid humanoid)
		{
			return LeftItemRef.Invoke(humanoid);
		}

		internal static ItemData HelmetItem(Humanoid humanoid)
		{
			return HelmetItemRef.Invoke(humanoid);
		}

		internal static VisEquipment GetVisEquipment(Humanoid humanoid)
		{
			return VisEquipmentRef.Invoke(humanoid);
		}

		internal static GameObject HelmetItemInstance(VisEquipment visEquipment)
		{
			return HelmetItemInstanceRef.Invoke(visEquipment);
		}

		internal static int AutoPickupMask(Player player)
		{
			return AutoPickupMaskRef.Invoke(player);
		}

		internal static ZNetView ItemNetView(ItemDrop item)
		{
			return ItemNetViewRef.Invoke(item);
		}

		internal static ref float CameraDistance(GameCamera camera)
		{
			return ref CameraDistanceRef.Invoke(camera);
		}

		internal static ref GameObject BallInstance(SE_Demister demister)
		{
			return ref BallInstanceRef.Invoke(demister);
		}

		internal static ref Vector3 BallVelocity(SE_Demister demister)
		{
			return ref BallVelocityRef.Invoke(demister);
		}

		internal static int CoverRayMask(SE_Demister demister)
		{
			return CoverRayMaskRef.Invoke(demister);
		}

		internal static ref float StatusTime(StatusEffect effect)
		{
			return ref StatusTimeRef.Invoke(effect);
		}

		internal static ref float StatusMessageTimer(StatusEffect effect)
		{
			return ref StatusMessageTimerRef.Invoke(effect);
		}

		internal static bool TakeInput(Character character)
		{
			return TakeInputCall(character);
		}

		internal static void UpdatePlacement(Player player, bool takeInput, float dt)
		{
			UpdatePlacementCall(player, takeInput, dt);
		}

		internal static void AddWord(Localization localization, string key, string text)
		{
			AddWordCall(localization, key, text);
		}
	}
	internal static class DvergrCircletCameraLight
	{
		private sealed class CustomSlotAdapter
		{
			private readonly MethodInfo? _getEquippedCirclet;

			private readonly MethodInfo? _getCircletVisuals;

			private readonly FieldInfo? _circletObject;

			internal CustomSlotAdapter(string modNamespace)
			{
				Type type = FindLoadedType(modNamespace + ".HumanoidExtension");
				Type type2 = FindLoadedType(modNamespace + ".VisEquipmentExtension");
				Type type3 = FindLoadedType(modNamespace + ".VisEquipmentCirclet");
				_getEquippedCirclet = type?.GetMethod("GetCirclet", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Humanoid) }, null);
				_getCircletVisuals = type2?.GetMethod("GetCircletData", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(VisEquipment) }, null);
				_circletObject = type3?.GetField("m_circletItemInstance", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}

			internal bool TryGetCirclet(Player player, VisEquipment visualEquipment, out ItemData? item, out GameObject? circletObject)
			{
				item = null;
				circletObject = null;
				if (_getEquippedCirclet == null || _getCircletVisuals == null || _circletObject == null)
				{
					return false;
				}
				try
				{
					SingleArgumentBuffer[0] = player;
					object? obj = _getEquippedCirclet.Invoke(null, SingleArgumentBuffer);
					item = (ItemData?)((obj is ItemData) ? obj : null);
					SingleArgumentBuffer[0] = visualEquipment;
					object obj2 = _getCircletVisuals.Invoke(null, SingleArgumentBuffer);
					circletObject = (GameObject?)((obj2 == null) ? null : /*isinst with value type is only supported in some contexts*/);
					return item != null && Object.op_Implicit((Object)(object)circletObject);
				}
				catch
				{
					return false;
				}
				finally
				{
					SingleArgumentBuffer[0] = null;
				}
			}

			private static Type? FindLoadedType(string fullName)
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				for (int i = 0; i < assemblies.Length; i++)
				{
					Type type = assemblies[i].GetType(fullName, throwOnError: false);
					if (type != null)
					{
						return type;
					}
				}
				return null;
			}
		}

		private sealed class CameraLightCopy
		{
			internal readonly Light SourceLight;

			internal readonly Light CopiedLight;

			internal readonly GameObject CopiedObject;

			internal int SourceCullingMask;

			internal CameraLightCopy(Light sourceLight, Light copiedLight, GameObject copiedObject)
			{
				SourceLight = sourceLight;
				CopiedLight = copiedLight;
				CopiedObject = copiedObject;
				SourceCullingMask = sourceLight.cullingMask;
			}
		}

		private const float EquipmentRefreshInterval = 0.25f;

		private const float LightSettingsRefreshInterval = 0.1f;

		private const string OriginalColor = "Original";

		private static readonly Dictionary<int, CameraLightCopy> CameraLightCopies = new Dictionary<int, CameraLightCopy>();

		private static readonly HashSet<int> EquippedLightIds = new HashSet<int>();

		private static readonly List<int> LightsToRemove = new List<int>();

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

		private static readonly object?[] SingleArgumentBuffer = new object[1];

		private static readonly CustomSlotAdapter[] CustomSlotAdapters = new CustomSlotAdapter[2]
		{
			new CustomSlotAdapter("CircletExtended"),
			new CustomSlotAdapter("RaziCirclet")
		};

		private static float _nextEquipmentRefresh;

		private static float _nextLightSettingsRefresh;

		private static float _nextWarningTime;

		private static string _cachedColorSetting = string.Empty;

		private static bool _cachedColorOverride;

		private static Color _cachedColor;

		internal static void Update(GameCamera camera)
		{
			try
			{
				UpdateLights(camera);
			}
			catch (Exception ex)
			{
				if (Time.time >= _nextWarningTime)
				{
					_nextWarningTime = Time.time + 2f;
					Plugin.Log.LogWarning((object)("Dvergr camera light failed: " + ex.Message));
				}
				Cleanup();
			}
		}

		internal static void Cleanup()
		{
			foreach (CameraLightCopy value in CameraLightCopies.Values)
			{
				RestoreSourceLight(value);
			}
			CameraLightCopies.Clear();
			EquippedLightIds.Clear();
			LightsToRemove.Clear();
			CircletLights.Clear();
			SingleArgumentBuffer[0] = null;
			_nextEquipmentRefresh = 0f;
			_nextLightSettingsRefresh = 0f;
			_nextWarningTime = 0f;
		}

		private static void UpdateLights(GameCamera camera)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: 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_00e7: 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_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)camera) || !Object.op_Implicit((Object)(object)localPlayer) || Plugin.followDvergrCircletLight.Value != Plugin.Toggle.On)
			{
				if (CameraLightCopies.Count != 0)
				{
					Cleanup();
				}
				return;
			}
			float time = Time.time;
			if (time >= _nextEquipmentRefresh)
			{
				_nextEquipmentRefresh = time + 0.25f;
				RefreshEquippedLights(localPlayer);
			}
			if (CameraLightCopies.Count == 0)
			{
				return;
			}
			bool flag = time >= _nextLightSettingsRefresh;
			if (flag)
			{
				_nextLightSettingsRefresh = time + 0.1f;
			}
			Transform transform = ((Component)camera).transform;
			Vector3 val = transform.up * Plugin.helmetLightOffsetUp.Value;
			val += transform.forward * Plugin.helmetLightOffsetForward.Value;
			val += transform.right * Plugin.helmetLightOffsetRight.Value;
			Vector3 position = transform.position + val;
			Quaternion rotation = transform.rotation;
			foreach (CameraLightCopy value in CameraLightCopies.Values)
			{
				if (!Object.op_Implicit((Object)(object)value.SourceLight))
				{
					_nextEquipmentRefresh = 0f;
				}
				else
				{
					MoveLightToCamera(value, position, rotation, flag);
				}
			}
		}

		private static void RefreshEquippedLights(Player player)
		{
			EquippedLightIds.Clear();
			VisEquipment visEquipment = Access.GetVisEquipment((Humanoid)(object)player);
			if (Object.op_Implicit((Object)(object)visEquipment))
			{
				if (IsDvergrCirclet(Access.HelmetItem((Humanoid)(object)player)) && Object.op_Implicit((Object)(object)Access.HelmetItemInstance(visEquipment)))
				{
					AddCircletLights(Access.HelmetItemInstance(visEquipment));
				}
				CustomSlotAdapter[] customSlotAdapters = CustomSlotAdapters;
				for (int i = 0; i < customSlotAdapters.Length; i++)
				{
					if (customSlotAdapters[i].TryGetCirclet(player, visEquipment, out ItemData item, out GameObject circletObject) && IsDvergrCirclet(item) && Object.op_Implicit((Object)(object)circletObject))
					{
						AddCircletLights(circletObject);
					}
				}
			}
			RemoveUnequippedLights();
		}

		private static bool IsDvergrCirclet(ItemData? item)
		{
			if (item == null)
			{
				return false;
			}
			if (!(Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : string.Empty).StartsWith("HelmetDverger", StringComparison.OrdinalIgnoreCase))
			{
				return item.m_shared.m_name.IndexOf("helmet_dverger", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static void AddCircletLights(GameObject circletObject)
		{
			CircletLights.Clear();
			circletObject.GetComponentsInChildren<Light>(true, CircletLights);
			foreach (Light circletLight in CircletLights)
			{
				if (Object.op_Implicit((Object)(object)circletLight))
				{
					int instanceID = ((Object)circletLight).GetInstanceID();
					if (EquippedLightIds.Add(instanceID) && !CameraLightCopies.ContainsKey(instanceID))
					{
						CameraLightCopies.Add(instanceID, CreateCameraLightCopy(circletLight));
					}
				}
			}
		}

		private static void RemoveUnequippedLights()
		{
			LightsToRemove.Clear();
			foreach (KeyValuePair<int, CameraLightCopy> cameraLightCopy in CameraLightCopies)
			{
				if (!Object.op_Implicit((Object)(object)cameraLightCopy.Value.SourceLight) || !EquippedLightIds.Contains(cameraLightCopy.Key))
				{
					LightsToRemove.Add(cameraLightCopy.Key);
				}
			}
			foreach (int item in LightsToRemove)
			{
				RestoreSourceLight(CameraLightCopies[item]);
				CameraLightCopies.Remove(item);
			}
		}

		private static CameraLightCopy CreateCameraLightCopy(Light sourceLight)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			GameObject val = new GameObject("ShackMagicCam_DvergrLight_" + ((Object)sourceLight).name)
			{
				hideFlags = (HideFlags)61
			};
			CameraLightCopy cameraLightCopy = new CameraLightCopy(sourceLight, val.AddComponent<Light>(), val);
			SyncLightSettings(cameraLightCopy);
			sourceLight.cullingMask = 0;
			return cameraLightCopy;
		}

		private static void MoveLightToCamera(CameraLightCopy lightCopy, Vector3 position, Quaternion rotation, bool refreshSettings)
		{
			//IL_0037: 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)
			Light sourceLight = lightCopy.SourceLight;
			if (sourceLight.cullingMask != 0)
			{
				lightCopy.SourceCullingMask = sourceLight.cullingMask;
			}
			if (refreshSettings)
			{
				SyncLightSettings(lightCopy);
			}
			sourceLight.cullingMask = 0;
			Transform transform = lightCopy.CopiedObject.transform;
			transform.position = position;
			transform.rotation = rotation;
			((Behaviour)lightCopy.CopiedLight).enabled = ((Behaviour)sourceLight).enabled;
			bool activeInHierarchy = ((Component)sourceLight).gameObject.activeInHierarchy;
			if (lightCopy.CopiedObject.activeSelf != activeInHierarchy)
			{
				lightCopy.CopiedObject.SetActive(activeInHierarchy);
			}
		}

		private static void SyncLightSettings(CameraLightCopy lightCopy)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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)
			Light sourceLight = lightCopy.SourceLight;
			Light copiedLight = lightCopy.CopiedLight;
			Color color;
			bool flag = TryGetConfiguredColor(out color);
			copiedLight.type = sourceLight.type;
			copiedLight.color = (flag ? color : sourceLight.color);
			copiedLight.colorTemperature = sourceLight.colorTemperature;
			copiedLight.useColorTemperature = sourceLight.useColorTemperature && !flag;
			copiedLight.intensity = sourceLight.intensity * Plugin.helmetLightIntensityMultiplier.Value;
			copiedLight.range = sourceLight.range * Plugin.helmetLightRangeMultiplier.Value;
			copiedLight.spotAngle = sourceLight.spotAngle;
			copiedLight.cookie = sourceLight.cookie;
			copiedLight.cookieSize = sourceLight.cookieSize;
			copiedLight.shadows = GetConfiguredShadows(sourceLight.shadows);
			copiedLight.shadowStrength = sourceLight.shadowStrength;
			copiedLight.shadowResolution = sourceLight.shadowResolution;
			copiedLight.renderMode = sourceLight.renderMode;
			copiedLight.cullingMask = lightCopy.SourceCullingMask;
		}

		private static bool TryGetConfiguredColor(out Color color)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			string text = Plugin.helmetLightColor.Value ?? string.Empty;
			if (text != _cachedColorSetting)
			{
				CacheConfiguredColor(text);
			}
			color = _cachedColor;
			return _cachedColorOverride;
		}

		private static void CacheConfiguredColor(string setting)
		{
			_cachedColorSetting = setting;
			string text = setting.Trim();
			if (string.IsNullOrEmpty(text) || text.Equals("Original", StringComparison.OrdinalIgnoreCase))
			{
				_cachedColorOverride = false;
				return;
			}
			if (!text.StartsWith("#", StringComparison.Ordinal))
			{
				text = "#" + text;
			}
			_cachedColorOverride = ColorUtility.TryParseHtmlString(text, ref _cachedColor);
		}

		private static LightShadows GetConfiguredShadows(LightShadows sourceShadows)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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)
			return (LightShadows)(Plugin.helmetLightShadows.Value switch
			{
				Plugin.CameraLightShadows.Off => 0, 
				Plugin.CameraLightShadows.Hard => 1, 
				Plugin.CameraLightShadows.Soft => 2, 
				_ => sourceShadows, 
			});
		}

		private static void RestoreSourceLight(CameraLightCopy lightCopy)
		{
			if (Object.op_Implicit((Object)(object)lightCopy.SourceLight))
			{
				lightCopy.SourceLight.cullingMask = lightCopy.SourceCullingMask;
			}
			if (Object.op_Implicit((Object)(object)lightCopy.CopiedObject))
			{
				Object.Destroy((Object)(object)lightCopy.CopiedObject);
			}
		}
	}
	[HarmonyPatch(typeof(Localization), "SetupLanguage")]
	internal static class Localization_SetupLanguage_Patch
	{
		private static void Postfix(Localization __instance)
		{
			Utils.AddLocalizations(__instance);
			PickupBlockedHud.LanguageChanged();
		}
	}
	[HarmonyPatch(typeof(CraftingStation), "HaveBuildStationInRange")]
	internal static class CraftingStation_HaveBuildStationInRange_Patch
	{
		private static void Postfix(string name, Vector3 point, ref CraftingStation __result)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)__result) && Utils.InBuildMode())
			{
				CraftingStation val = Utils.FindCameraStation(name, point);
				if (val != null)
				{
					__result = val;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class Player_BuildCameraPlacementDistance_Patch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.DeclaredMethod(typeof(Player), "PieceRayTest", (Type[])null, (Type[])null);
			yield return AccessTools.DeclaredMethod(typeof(Player), "UpdateWearNTearHover", (Type[])null, (Type[])null);
			yield return AccessTools.DeclaredMethod(typeof(Player), "CopyPiece", (Type[])null, (Type[])null);
			yield return AccessTools.DeclaredMethod(typeof(Player), "RemovePiece", (Type[])null, (Type[])null);
		}

		private static void Prefix(ref float ___m_maxPlaceDistance, out float __state)
		{
			__state = ___m_maxPlaceDistance;
			if (Utils.InBuildMode())
			{
				___m_maxPlaceDistance = Mathf.Max(___m_maxPlaceDistance, Plugin.distanceCanBuildFromAvatar.Value);
			}
		}

		private static Exception Finalizer(Exception __exception, ref float ___m_maxPlaceDistance, float __state)
		{
			___m_maxPlaceDistance = __state;
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Player), "SetLocalPlayer")]
	internal static class Player_SetLocalPlayer_Patch
	{
		private static void Postfix()
		{
			PickupBlockedHud.Cleanup();
			Utils.DisableBuildMode();
		}
	}
	[HarmonyPatch(typeof(Player), "OnDeath")]
	internal static class Player_OnDeath_Patch
	{
		private static void Postfix()
		{
			Utils.DisableBuildMode();
		}
	}
	[HarmonyPatch(typeof(Player), "OnDestroy")]
	internal static class Player_OnDestroy_Patch
	{
		private static void Prefix(Player __instance)
		{
			if (Utils.IsLocalPlayer(__instance))
			{
				Utils.DisableBuildMode();
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	internal static class Player_Update_Patch
	{
		private static readonly string[] HotbarButtons = new string[8] { "Hotbar1", "Hotbar2", "Hotbar3", "Hotbar4", "Hotbar5", "Hotbar6", "Hotbar7", "Hotbar8" };

		private static readonly string[] HotbarAltButtons = new string[8] { "Hotbar1Alt", "Hotbar2Alt", "Hotbar3Alt", "Hotbar4Alt", "Hotbar5Alt", "Hotbar6Alt", "Hotbar7Alt", "Hotbar8Alt" };

		private static void Prefix(Player __instance, ref bool __runOriginal)
		{
			if (!Utils.IsLocalPlayer(__instance) || !Utils.InBuildMode())
			{
				return;
			}
			if (!Utils.CanUseCamera())
			{
				Utils.ShowComfortMessage();
				Utils.DisableBuildMode();
				return;
			}
			if (Utils.ShouldDeactivateBuildMode(__instance))
			{
				Utils.DisableBuildMode();
				return;
			}
			if (((Character)__instance).IsTeleporting())
			{
				Utils.DisableBuildMode();
				return;
			}
			__runOriginal = false;
			if (!Access.TakeInput((Character)(object)__instance))
			{
				return;
			}
			for (int i = 0; i < HotbarButtons.Length; i++)
			{
				if (ZInput.GetButtonDown(HotbarButtons[i]) || ZInput.GetButtonDown(HotbarAltButtons[i]))
				{
					__instance.UseHotbarItem(i + 1);
				}
			}
			if ((ZInput.GetButtonDown("Hide") || ZInput.GetButtonDown("JoyHide")) && (Access.RightItem((Humanoid)(object)__instance) != null || Access.LeftItem((Humanoid)(object)__instance) != null) && !((Character)__instance).InAttack())
			{
				((Humanoid)__instance).HideHandItems(false, true);
			}
			Access.UpdatePlacement(__instance, takeInput: true, Time.deltaTime);
		}

		private static void Postfix(Player __instance)
		{
			if (!Utils.IsLocalPlayer(__instance) || !Utils.ToggleKeyDown())
			{
				return;
			}
			if (Utils.InBuildMode())
			{
				if (Access.TakeInput((Character)(object)__instance))
				{
					Utils.DisableBuildMode();
				}
			}
			else if (!Access.TakeInput((Character)(object)__instance))
			{
				Utils.LogWhenVerbose("Build Mode not enabled because chat, console, menu, inventory, map, or similar is open.");
			}
			else if (!Utils.ToolIsEquipped(__instance))
			{
				Utils.LogWhenVerbose("Build Mode not enabled because hammer is not equipped.");
			}
			else if (!Utils.BuildStationInRange(__instance))
			{
				Utils.LogWhenVerbose("Build Mode not enabled because no build station (e.g. workbench) is in range.");
			}
			else if (!Utils.CanUseCamera())
			{
				Utils.ShowComfortMessage();
				Utils.LogWhenVerbose("Build Mode not enabled because the cozy and comfort requirement is not met.");
			}
			else if (GameCamera.InFreeFly())
			{
				Utils.LogWhenVerbose("Build Mode not enabled because the game's own free-fly camera is active.");
			}
			else
			{
				Utils.EnableBuildMode();
			}
		}
	}
	[HarmonyPatch(typeof(PlayerController), "TakeInput")]
	internal static class PlayerController_TakeInput_Patch
	{
		private static void Prefix(ref bool __result, ref bool __runOriginal)
		{
			if (Utils.InBuildMode())
			{
				__result = false;
				__runOriginal = false;
			}
		}
	}
	[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
	[HarmonyBefore(new string[] { "Azumatt.FirstPersonMode" })]
	[HarmonyPriority(700)]
	internal static class GameCamera_UpdateCamera_Patch
	{
		private const float PickupScanInterval = 0.1f;

		private static float _nextPickupScan;

		private static void Prefix(float dt, GameCamera __instance, ref bool __runOriginal)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (!Utils.InBuildMode())
			{
				_nextPickupScan = 0f;
				return;
			}
			Utils.KeepOutOfFirstPerson(__instance);
			Utils.UpdateBuildCamera(dt, __instance);
			if (Time.time >= _nextPickupScan)
			{
				_nextPickupScan = Time.time + 0.1f;
				if (Utils.TryGetAutoPickupPlayer(out Player player) && WardAccess.Check(player.GetPlayerID(), ((Component)__instance).transform.position))
				{
					Utils.AutoPickup(__instance, player);
				}
			}
			__runOriginal = false;
		}

		private static void Postfix(GameCamera __instance)
		{
			if (Utils.InBuildMode())
			{
				DvergrCircletCameraLight.Update(__instance);
			}
		}
	}
	internal static class PickupBlockedHud
	{
		private const float VisibilityCheckInterval = 0.2f;

		private const float PanelWidth = 460f;

		private const float HorizontalPadding = 18f;

		private const float TopPadding = 12f;

		private const float BottomPadding = 14f;

		private const float TextSpacing = 4f;

		private static GameObject _panel = null;

		private static RectTransform _panelRect = null;

		private static TextMeshProUGUI _titleText = null;

		private static TextMeshProUGUI _bodyText = null;

		private static float _nextVisibilityCheck;

		private static float _lastHudX = float.NaN;

		private static float _lastHudY = float.NaN;

		private static int _lastComfortLevel = -1;

		private static int _lastFontSize = -1;

		internal static void Update()
		{
			if (Time.time < _nextVisibilityCheck)
			{
				return;
			}
			_nextVisibilityCheck = Time.time + 0.2f;
			if (Hud.IsUserHidden() || !Utils.ShouldShowPickupWarning())
			{
				Hide();
				return;
			}
			if (!Object.op_Implicit((Object)(object)_panel))
			{
				_panelRect = null;
				_titleText = null;
				_bodyText = null;
				if (!CreatePanel())
				{
					return;
				}
			}
			GameObject panel = _panel;
			if (Object.op_Implicit((Object)(object)panel))
			{
				bool num = !panel.activeSelf;
				if (num || NeedsRefresh())
				{
					RefreshPanel();
				}
				if (num)
				{
					panel.SetActive(true);
				}
			}
		}

		internal static void LanguageChanged()
		{
			_lastComfortLevel = -1;
		}

		internal static void Cleanup()
		{
			if (Object.op_Implicit((Object)(object)_panel))
			{
				Object.Destroy((Object)(object)_panel);
			}
			_panel = null;
			_panelRect = null;
			_titleText = null;
			_bodyText = null;
			_nextVisibilityCheck = 0f;
			_lastHudX = float.NaN;
			_lastHudY = float.NaN;
			_lastComfortLevel = -1;
			_lastFontSize = -1;
		}

		private static bool CreatePanel()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			MessageHud instance = MessageHud.instance;
			Hud instance2 = Hud.instance;
			if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance2) || !Object.op_Implicit((Object)(object)instance.m_messageText) || !Object.op_Implicit((Object)(object)instance.m_messageText.font))
			{
				return false;
			}
			_panel = new GameObject("ShackMagicCam_PickupBlocked", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			_panel.SetActive(false);
			_panel.transform.SetParent(((Component)instance).transform, false);
			_panel.transform.SetAsLastSibling();
			_panelRect = (RectTransform)_panel.transform;
			Image component = _panel.GetComponent<Image>();
			((Graphic)component).raycastTarget = false;
			ApplyPanelStyle(component, instance2);
			_titleText = CreateText("Title", instance.m_messageText);
			_bodyText = CreateText("Body", instance.m_messageText);
			((TMP_Text)_titleText).fontStyle = (FontStyles)1;
			((TMP_Text)_titleText).alignment = (TextAlignmentOptions)257;
			((TMP_Text)_bodyText).alignment = (TextAlignmentOptions)257;
			((TMP_Text)_bodyText).textWrappingMode = (TextWrappingModes)1;
			return true;
		}

		private static TextMeshProUGUI CreateText(string name, TMP_Text fontSource)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer)
			});
			val.transform.SetParent(_panel.transform, false);
			TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).font = fontSource.font;
			((TMP_Text)obj).fontSharedMaterial = fontSource.fontSharedMaterial;
			((Graphic)obj).color = ((Graphic)fontSource).color;
			((Graphic)obj).raycastTarget = false;
			((TMP_Text)obj).enableAutoSizing = false;
			((TMP_Text)obj).overflowMode = (TextOverflowModes)0;
			return obj;
		}

		private static void ApplyPanelStyle(Image background, Hud hud)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			Image val = null;
			if (Object.op_Implicit((Object)(object)hud.m_pieceSelectionWindow))
			{
				Transform val2 = hud.m_pieceSelectionWindow.transform.Find("Bkg2");
				if (Object.op_Implicit((Object)(object)val2))
				{
					val = ((Component)val2).GetComponent<Image>();
				}
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				background.sprite = val.sprite;
				background.type = val.type;
				((Graphic)background).color = ((Graphic)val).color;
				background.pixelsPerUnitMultiplier = val.pixelsPerUnitMultiplier;
			}
			else
			{
				Plugin.Log.LogWarning((object)"Could not find the vanilla build-window background (Hud.m_pieceSelectionWindow/Bkg2) - using a flat colour.");
				((Graphic)background).color = new Color(0.06f, 0.055f, 0.045f, 0.92f);
			}
		}

		private static bool NeedsRefresh()
		{
			if (_lastComfortLevel != Plugin.minimumComfortLevel.Value)
			{
				return true;
			}
			if (_lastFontSize != Plugin.pickupHudFontSize.Value)
			{
				return true;
			}
			if (!Mathf.Approximately(_lastHudX, Plugin.pickupHudX.Value))
			{
				return true;
			}
			return !Mathf.Approximately(_lastHudY, Plugin.pickupHudY.Value);
		}

		private static void RefreshPanel()
		{
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: 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_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			_lastComfortLevel = Plugin.minimumComfortLevel.Value;
			_lastFontSize = Plugin.pickupHudFontSize.Value;
			_lastHudX = Plugin.pickupHudX.Value;
			_lastHudY = Plugin.pickupHudY.Value;
			((TMP_Text)_titleText).text = Localization.instance.Localize("$shackmagiccam_pickup_blocked_title");
			((TMP_Text)_bodyText).text = Localization.instance.Localize("$shackmagiccam_pickup_blocked", new string[1] { _lastComfortLevel.ToString() });
			((TMP_Text)_titleText).fontSize = Mathf.Max(18, _lastFontSize + 2);
			((TMP_Text)_bodyText).fontSize = _lastFontSize;
			float num = ((TMP_Text)_titleText).fontSize + 6f;
			float num2 = Mathf.Max(((TMP_Text)_bodyText).fontSize * 2.4f, ((TMP_Text)_bodyText).GetPreferredValues(((TMP_Text)_bodyText).text, 424f, 0f).y);
			float num3 = 12f + num + 4f + num2 + 14f;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(_lastHudX, _lastHudY);
			_panelRect.anchorMin = val;
			_panelRect.anchorMax = val;
			_panelRect.pivot = val;
			_panelRect.anchoredPosition = Vector2.zero;
			_panelRect.sizeDelta = new Vector2(460f, num3);
			((Transform)_panelRect).localScale = Vector3.one;
			RectTransform rectTransform = ((TMP_Text)_titleText).rectTransform;
			rectTransform.anchorMin = new Vector2(0f, 1f);
			rectTransform.anchorMax = new Vector2(1f, 1f);
			rectTransform.pivot = new Vector2(0.5f, 1f);
			rectTransform.anchoredPosition = new Vector2(0f, -12f);
			rectTransform.sizeDelta = new Vector2(-36f, num);
			RectTransform rectTransform2 = ((TMP_Text)_bodyText).rectTransform;
			rectTransform2.anchorMin = new Vector2(0f, 1f);
			rectTransform2.anchorMax = new Vector2(1f, 1f);
			rectTransform2.pivot = new Vector2(0.5f, 1f);
			rectTransform2.anchoredPosition = new Vector2(0f, -12f - num - 4f);
			rectTransform2.sizeDelta = new Vector2(-36f, num2);
		}

		private static void Hide()
		{
			if (Object.op_Implicit((Object)(object)_panel) && _panel.activeSelf)
			{
				_panel.SetActive(false);
			}
		}
	}
	[BepInPlugin("theshack.magiccam", "Shack Magic Cam", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		public enum RestrictionMode
		{
			Off,
			CameraNeedsCoziness,
			CameraPickUpNeedsCoziness
		}

		public enum CameraLightShadows
		{
			Original,
			Off,
			Hard,
			Soft
		}

		internal const string ModName = "Shack Magic Cam";

		internal const string ModVersion = "1.0.0";

		private const string ModGUID = "theshack.magiccam";

		private static readonly string[] ReplacedGUIDs = new string[2] { "com.jekkle.valheim.carturbuildcamera", "Azumatt.BuildCameraCHE" };

		private readonly Harmony _harmony = new Harmony("theshack.magiccam");

		private FileSystemWatcher? _configWatcher;

		private static readonly string ConfigFileName = "theshack.magiccam.cfg";

		private static readonly string ConfigFileFullPath = Paths.ConfigPath + Path.DirectorySeparatorChar + ConfigFileName;

		public static readonly ManualLogSource Log = Logger.CreateLogSource("Shack Magic Cam");

		private bool _standDown;

		internal static bool BuildCameraActive;

		internal static float CameraYaw;

		internal static float CameraPitch;

		internal static ConfigEntry<float> distanceCanBuildFromAvatar = null;

		internal static ConfigEntry<float> distanceCanBuildFromWorkbench = null;

		internal static ConfigEntry<float> resourcePickupRange = null;

		internal static ConfigEntry<float> cameraRangeMultiplier = null;

		internal static ConfigEntry<float> cameraMoveSpeedMultiplier = null;

		internal static ConfigEntry<float> cameraTerrainClearance = null;

		internal static ConfigEntry<RestrictionMode> restrictionMode = null;

		internal static ConfigEntry<int> minimumComfortLevel = null;

		internal static ConfigEntry<Toggle> moveWithRespectToWorld = null;

		internal static ConfigEntry<KeyboardShortcut> toggleBuildMode = null;

		internal static ConfigEntry<Toggle> verboseLogging = null;

		internal static ConfigEntry<Toggle> demisterFollowCamera = null;

		internal static ConfigEntry<float> demisterRangeMultiplier = null;

		internal static ConfigEntry<Toggle> followDvergrCircletLight = null;

		internal static ConfigEntry<float> helmetLightOffsetForward = null;

		internal static ConfigEntry<float> helmetLightOffsetUp = null;

		internal static ConfigEntry<float> helmetLightOffsetRight = null;

		internal static ConfigEntry<float> helmetLightIntensityMultiplier = null;

		internal static ConfigEntry<float> helmetLightRangeMultiplier = null;

		internal static ConfigEntry<string> helmetLightColor = null;

		internal static ConfigEntry<CameraLightShadows> helmetLightShadows = null;

		internal static ConfigEntry<float> pickupHudX = null;

		internal static ConfigEntry<float> pickupHudY = null;

		internal static ConfigEntry<int> pickupHudFontSize = null;

		internal static ConfigEntry<Toggle> invertControllerLookHorizontal = null;

		internal static ConfigEntry<Toggle> invertControllerLookVertical = null;

		internal static ConfigEntry<Toggle> invertMouseLookHorizontal = null;

		internal static ConfigEntry<Toggle> invertMouseLookVertical = null;

		private void Awake()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Expected O, but got Unknown
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Expected O, but got Unknown
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Expected O, but got Unknown
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Expected O, but got Unknown
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Expected O, but got Unknown
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Expected O, but got Unknown
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Expected O, but got Unknown
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_034f: Expected O, but got Unknown
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Expected O, but got Unknown
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fd: Expected O, but got Unknown
			//IL_042b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0436: Expected O, but got Unknown
			//IL_045b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0466: Expected O, but got Unknown
			//IL_053a: Unknown result type (might be due to invalid IL or missing references)
			distanceCanBuildFromAvatar = config("General", "Distance Can Build From Avatar", 100f, new ConfigDescription("Distance from your avatar that you can build or repair. (Valheim default is 8)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 500f), Array.Empty<object>()));
			distanceCanBuildFromWorkbench = config("General", "Distance Can Build From Workbench", 100f, new ConfigDescription("Maximum distance between the build camera and its workbench/stonecutter/etc. This does not change the station's actual build or player-base radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 500f), Array.Empty<object>()));
			resourcePickupRange = config("General", "Resource Pickup Range", 2f, new ConfigDescription("Distance from which you can pick up resources on the ground while in build mode. (Valheim default is 2)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 100f), Array.Empty<object>()));
			cameraRangeMultiplier = config("General", "Camera Range Multiplier", 1f, new ConfigDescription("Changes maximum range camera can move away from the build station. 1 means the build station's range, 2 means twice the build station range, etc.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			cameraMoveSpeedMultiplier = config("General", "Camera Move Speed Multiplier", 3f, new ConfigDescription("Multiplies the speed at which the build camera pans (i.e. moves around).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
			cameraTerrainClearance = config("General", "Camera Terrain Clearance", 1f, new ConfigDescription("Radius kept clear around the detached camera so it cannot cross terrain or a HearthBelow cave wall.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), Array.Empty<object>()));
			restrictionMode = config("General", "Restriction Mode", RestrictionMode.CameraPickUpNeedsCoziness, "Off: no cozy restriction. CameraNeedsCoziness: cozy is required to enter and stay in camera mode. CameraPickUpNeedsCoziness: camera entry is allowed, but camera pickup requires cozy.");
			minimumComfortLevel = config("General", "Minimum Comfort Level", 1, new ConfigDescription("Minimum comfort required by the selected restriction mode.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30), Array.Empty<object>()));
			moveWithRespectToWorld = config("General", "Move With Respect To World", Toggle.Off, "When true, camera panning input (e.g. pressing WASD) moves the camera with respect to the world coordinates. This means that turning the camera has no effect on the direction of movement. For example, pressing W will always move the camera toward the world's 'North', as opposed to the direction the camera is currently facing.");
			toggleBuildMode = config<KeyboardShortcut>("Hotkeys", "Toggle build mode", new KeyboardShortcut((KeyCode)121, Array.Empty<KeyCode>()), "See https://docs.unity3d.com/ScriptReference/KeyCode.html for the names of all key codes. To add one or more modifier keys, separate them with +, like so: Toggle build mode = Y + LeftControl", synchronizedSetting: false);
			verboseLogging = config("General", "Verbose Logging", Toggle.Off, "When true, increases verbosity of logging. Enable this if you're wondering why you're unable to enable the build camera.", synchronizedSetting: false);
			demisterFollowCamera = config("Mist", "Demister Follow Camera", Toggle.On, "When enabled and you have the Demister status effect (Wisplight), the demister ball will follow the build camera instead of your character while in build mode.");
			demisterRangeMultiplier = config("Mist", "Demister Range Multiplier", 1f, new ConfigDescription("Multiplier for the demister's mist-clearing range while in build mode. Higher values clear more mist. (Vanilla: 1.0x)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			followDvergrCircletLight = config("Helmet Light", "Follow Dvergr Circlet Light", Toggle.On, "Moves the equipped Dvergr circlet light to the detached camera. Also supports CircletExtended and RaziCirclet custom slots when installed.");
			helmetLightOffsetForward = config("Helmet Light", "Camera Light Forward/Back Offset", 0.65f, new ConfigDescription("Circlet light offset on the camera's forward axis.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f), Array.Empty<object>()), synchronizedSetting: false);
			helmetLightOffsetUp = config("Helmet Light", "Camera Light Up/Down Offset", -0.08f, new ConfigDescription("Circlet light offset on the camera's up axis.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f), Array.Empty<object>()), synchronizedSetting: false);
			helmetLightOffsetRight = config("Helmet Light", "Camera Light Left/Right Offset", 0f, new ConfigDescription("Circlet light offset on the camera's right axis. Negative values move it left.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-5f, 5f), Array.Empty<object>()), synchronizedSetting: false);
			helmetLightIntensityMultiplier = config("Helmet Light", "Camera Light Intensity Multiplier", 1f, new ConfigDescription("Multiplies the equipped circlet light's current intensity.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			helmetLightRangeMultiplier = config("Helmet Light", "Camera Light Range Multiplier", 1f, new ConfigDescription("Multiplies the equipped circlet light's current range.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			helmetLightColor = config("Helmet Light", "Camera Light Color", "Original", "Original uses the equipped circlet light color. Otherwise use a hex color such as FFD27F or FFD27FFF.");
			helmetLightShadows = config("Helmet Light", "Camera Light Shadows", CameraLightShadows.Original, "Original uses the equipped circlet light's shadow mode. Off, Hard, and Soft override it.");
			pickupHudX = config("HUD", "Pickup Blocked HUD X", 0.3f, new ConfigDescription("Horizontal pickup-blocked message position as a screen ratio.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()), synchronizedSetting: false);
			pickupHudY = config("HUD", "Pickup Blocked HUD Y", 0.3f, new ConfigDescription("Vertical pickup-blocked message position (1 = top, 0 = bottom).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()), synchronizedSetting: false);
			pickupHudFontSize = config("HUD", "Pickup Blocked HUD Font Size", 19, new ConfigDescription("Pickup-blocked message body size. The font and panel styling come from Valheim's HUD.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(12, 32), Array.Empty<object>()), synchronizedSetting: false);
			invertControllerLookHorizontal = config("Controls", "Invert Controller Look Horizontal", Toggle.Off, "Inverts the horizontal (left/right) look axis for the controller right stick while in build camera mode.", synchronizedSetting: false);
			invertControllerLookVertical = config("Controls", "Invert Controller Look Vertical", Toggle.Off, "Inverts the vertical (up/down) look axis for the controller right stick while in build camera mode.", synchronizedSetting: false);
			invertMouseLookHorizontal = config("Controls", "Invert Mouse Look Horizontal", Toggle.Off, "Inverts the horizontal (left/right) look axis for the mouse while in build camera mode.", synchronizedSetting: false);
			invertMouseLookVertical = config("Controls", "Invert Mouse Look Vertical", Toggle.Off, "Inverts the vertical (up/down) look axis for the mouse while in build camera mode. This is separate from the game's built-in mouse invert setting.", synchronizedSetting: false);
			try
			{
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
			}
			catch (Exception ex)
			{
				_standDown = true;
				Log.LogWarning((object)("Patching failed, build camera disabled: " + ex.Message));
				return;
			}
			Utils.AddLocalizations(Localization.instance);
			SetupWatcher();
			Log.LogInfo((object)string.Format("{0} {1} ready (toggle: {2}).", "Shack Magic Cam", "1.0.0", toggleBuildMode.Value));
		}

		private void Start()
		{
			if (_standDown)
			{
				return;
			}
			string[] replacedGUIDs = ReplacedGUIDs;
			foreach (string text in replacedGUIDs)
			{
				if (Chainloader.PluginInfos.TryGetValue(text, out var value))
				{
					Harmony.UnpatchID(text);
					if (Object.op_Implicit((Object)(object)value.Instance))
					{
						((Behaviour)value.Instance).enabled = false;
					}
					Log.LogWarning((object)string.Format("{0} {1} is also installed - turned its patches off, {2} runs the build camera. Remove it to silence this.", value.Metadata.Name, value.Metadata.Version, "Shack Magic Cam"));
				}
			}
		}

		private void Update()
		{
			if (!_standDown)
			{
				PickupBlockedHud.Update();
			}
		}

		private void OnDestroy()
		{
			if (_configWatcher != null)
			{
				_configWatcher.EnableRaisingEvents = false;
				_configWatcher.Changed -= ReadConfigValues;
				_configWatcher.Created -= ReadConfigValues;
				_configWatcher.Renamed -= ReadConfigValues;
				_configWatcher.Dispose();
				_configWatcher = null;
			}
			PickupBlockedHud.Cleanup();
			Utils.DisableBuildMode();
			_harmony.UnpatchSelf();
			((BaseUnityPlugin)this).Config.Save();
		}

		private void SetupWatcher()
		{
			_configWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			_configWatcher.Changed += ReadConfigValues;
			_configWatcher.Created += ReadConfigValues;
			_configWatcher.Renamed += ReadConfigValues;
			_configWatcher.IncludeSubdirectories = false;
			_configWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			_configWatcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				Log.LogDebug((object)"ReadConfigValues called");
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch
			{
				Log.LogError((object)("There was an issue loading your " + ConfigFileName));
				Log.LogError((object)"Please check your config entries for spelling and format!");
			}
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = synchronizedSetting
			} });
			return ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}
	}
	[HarmonyPatch(typeof(SE_Demister), "UpdateStatusEffect")]
	public static class SE_DemisterCameraPatch
	{
		private static GameObject _trackedBall;

		private static ParticleSystemForceField _trackedForceField;

		private static float _originalForceFieldRange;

		public static bool Prefix(SE_Demister __instance, float dt)
		{
			Character character = ((StatusEffect)__instance).m_character;
			Player val = (Player)(object)((character is Player) ? character : null);
			GameCamera instance = GameCamera.instance;
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)instance) || !Utils.IsLocalPlayer(val) || !Utils.InBuildMode() || Plugin.demisterFollowCamera.Value != Plugin.Toggle.On)
			{
				RestoreNormalForceField();
				return true;
			}
			AgeStatusEffect((StatusEffect)(object)__instance, dt);
			UpdateForceFieldRange(__instance);
			UpdateDemisterForCamera(__instance, val, ((Component)instance).transform, dt);
			return false;
		}

		private static void AgeStatusEffect(StatusEffect effect, float dt)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			Access.StatusTime(effect) += dt;
			if (!(effect.m_repeatInterval <= 0f) && !string.IsNullOrEmpty(effect.m_repeatMessage))
			{
				ref float reference = ref Access.StatusMessageTimer(effect);
				reference += dt;
				if (reference > effect.m_repeatInterval)
				{
					reference = 0f;
					effect.m_character.Message(effect.m_repeatMessageType, effect.m_repeatMessage, 0, (Sprite)null, false);
				}
			}
		}

		private static void UpdateForceFieldRange(SE_Demister instance)
		{
			GameObject val = Access.BallInstance(instance);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			if ((Object)(object)_trackedBall != (Object)(object)val || !Object.op_Implicit((Object)(object)_trackedForceField))
			{
				RestoreNormalForceField();
				ParticleSystemForceField componentInChildren = val.GetComponentInChildren<ParticleSystemForceField>();
				if (!Object.op_Implicit((Object)(object)componentInChildren))
				{
					return;
				}
				_trackedBall = val;
				_trackedForceField = componentInChildren;
				_originalForceFieldRange = componentInChildren.endRange;
			}
			_trackedForceField.endRange = _originalForceFieldRange * Plugin.demisterRangeMultiplier.Value;
		}

		private static void RestoreNormalForceField()
		{
			if (Object.op_Implicit((Object)(object)_trackedForceField))
			{
				_trackedForceField.endRange = _originalForceFieldRange;
			}
			_trackedBall = null;
			_trackedForceField = null;
			_originalForceFieldRange = 0f;
		}

		private static void UpdateDemisterForCamera(SE_Demister instance, Player player, Transform camera, float dt)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_0109: 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_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: 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_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = camera.position;
			Vector3 forward = camera.forward;
			ref GameObject reference = ref Access.BallInstance(instance);
			ref Vector3 reference2 = ref Access.BallVelocity(instance);
			if (!Object.op_Implicit((Object)(object)reference))
			{
				reference = Object.Instantiate<GameObject>(instance.m_ballPrefab, position + forward * 0.5f, Quaternion.identity);
				return;
			}
			bool num = IsUnderRoof(instance, position);
			Transform transform = reference.transform;
			Vector3 val = transform.position;
			Vector3 val2 = (num ? instance.m_offsetInterior : instance.m_offset);
			float num2 = (num ? instance.m_noiseDistanceInterior : instance.m_noiseDistance);
			Vector3 val3 = camera.right * val2.x + camera.up * val2.y + forward * val2.z;
			Vector3 val4 = position + val3;
			float num3 = Time.time * instance.m_noiseSpeed;
			Vector3 val5 = new Vector3(Mathf.Sin(num3 * 4f), Mathf.Sin(num3 * 2f) * instance.m_noiseDistanceYScale, Mathf.Cos(num3 * 5f)) * num2;
			Vector3 val6 = val4 + val5;
			Vector3 val7 = val6 - val;
			float sqrMagnitude = ((Vector3)(ref val7)).sqrMagnitude;
			float num4 = instance.m_maxDistance * instance.m_maxDistance;
			if (sqrMagnitude > num4 * 4f)
			{
				val = val6;
			}
			else if (sqrMagnitude > num4)
			{
				val = val6 - val7 * (instance.m_maxDistance / Mathf.Sqrt(sqrMagnitude));
			}
			val7 = val6 - val;
			float sqrMagnitude2 = ((Vector3)(ref val7)).sqrMagnitude;
			if (sqrMagnitude2 > 1E-06f)
			{
				reference2 += val7 * (instance.m_ballAcceleration * dt / Mathf.Sqrt(sqrMagnitude2));
			}
			float sqrMagnitude3 = ((Vector3)(ref reference2)).sqrMagnitude;
			float num5 = instance.m_ballMaxSpeed * instance.m_ballMaxSpeed;
			if (sqrMagnitude3 > num5)
			{
				reference2 *= instance.m_ballMaxSpeed / Mathf.Sqrt(sqrMagnitude3);
			}
			if (!num)
			{
				reference2 += ((Character)player).GetVelocity() * instance.m_characterVelocityFactor * dt;
			}
			reference2 -= reference2 * instance.m_ballFriction;
			transform.position = val + reference2 * dt;
			transform.rotation *= Quaternion.Euler(instance.m_rotationSpeed, 0f, instance.m_rotationSpeed * 0.5321f);
		}

		private static bool IsUnderRoof(SE_Demister instance, Vector3 cameraPosition)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit val = default(RaycastHit);
			return Physics.Raycast(cameraPosition, Vector3.up, ref val, 4f, Access.CoverRayMask(instance));
		}

		internal static void CleanupBall(GameObject ball)
		{
			if ((Object)(object)_trackedBall == (Object)(object)ball)
			{
				RestoreNormalForceField();
			}
		}

		internal static void Cleanup()
		{
			RestoreNormalForceField();
		}
	}
	[HarmonyPatch(typeof(SE_Demister), "RemoveEffects")]
	public static class SE_DemisterCleanupPatch
	{
		[HarmonyPrefix]
		public static void RemoveEffects_Prefix(SE_Demister __instance)
		{
			SE_DemisterCameraPatch.CleanupBall(Access.BallInstance(__instance));
		}
	}
	public static class Utils
	{
		private const float ComfortRefreshInterval = 0.2f;

		private static readonly Collider[] NearbyPickupColliders = (Collider[])(object)new Collider[128];

		private static readonly HashSet<int> NearbyPickupItemIds = new HashSet<int>();

		private static readonly Dictionary<string, CraftingStation> CameraStationsByName = new Dictionary<string, CraftingStation>();

		private static readonly int TerrainMask = LayerMask.GetMask(new string[1] { "terrain" });

		private static CraftingStation? _cameraStation;

		private static Vector3 _lastSafeCameraPosition;

		private static bool _hasLastSafeCameraPosition;

		private static Player? _comfortPlayer;

		private static bool _hasRequiredComfort;

		private static float _nextComfortRefresh;

		private static float _nextComfortMessageTime;

		private const float AboveFirstPerson = 0.01f;

		private static float? _distanceBeforeBuild;

		internal static void LogWhenVerbose(string message)
		{
			if (Plugin.verboseLogging.Value == Plugin.Toggle.On)
			{
				if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					((Character)Player.m_localPlayer).Message((MessageType)1, message, 0, (Sprite)null, false);
				}
				Plugin.Log.LogInfo((object)message);
			}
		}

		public static bool InBuildMode()
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return Plugin.BuildCameraActive;
			}
			return false;
		}

		internal static void KeepOutOfFirstPerson(GameCamera camera)
		{
			ref float reference = ref Access.CameraDistance(camera);
			if (!(reference > 0.001f))
			{
				float valueOrDefault = _distanceBeforeBuild.GetValueOrDefault();
				if (!_distanceBeforeBuild.HasValue)
				{
					valueOrDefault = reference;
					_distanceBeforeBuild = valueOrDefault;
				}
				reference = 0.01f;
			}
		}

		private static void RestoreCameraDistance()
		{
			float? distanceBeforeBuild = _distanceBeforeBuild;
			if (distanceBeforeBuild.HasValue)
			{
				float valueOrDefault = distanceBeforeBuild.GetValueOrDefault();
				if (Object.op_Implicit((Object)(object)GameCamera.instance))
				{
					Access.CameraDistance(GameCamera.instance) = valueOrDefault;
				}
			}
			_distanceBeforeBuild = null;
		}

		internal static void DisableBuildMode()
		{
			Plugin.BuildCameraActive = false;
			RestoreCameraDistance();
			_cameraStation = null;
			CameraStationsByName.Clear();
			_hasLastSafeCameraPosition = false;
			_comfortPlayer = null;
			_hasRequiredComfort = false;
			_nextComfortRefresh = 0f;
			_nextComfortMessageTime = 0f;
			DvergrCircletCameraLight.Cleanup();
			SE_DemisterCameraPatch.Cleanup();
		}

		internal static bool ToggleKeyDown()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Plugin.toggleBuildMode.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !Input.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
			{
				if (!Input.GetKey(modifier))
				{
					return false;
				}
			}
			return true;
		}

		internal static void EnableBuildMode()
		{
			//IL_0016: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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)
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && TryFindCameraStation(((Component)Player.m_localPlayer).transform.position, out _cameraStation))
			{
				Plugin.BuildCameraActive = true;
				Quaternion rotation = ((Component)((Character)Player.m_localPlayer).m_eye).transform.rotation;
				Plugin.CameraPitch = Mathf.DeltaAngle(0f, ((Quaternion)(ref rotation)).eulerAngles.x);
				Plugin.CameraYaw = ((Quaternion)(ref rotation)).eulerAngles.y;
				if (Object.op_Implicit((Object)(object)GameCamera.instance))
				{
					_lastSafeCameraPosition = ((Component)GameCamera.instance).transform.position;
					_hasLastSafeCameraPosition = true;
				}
				((Character)Player.m_localPlayer).Message((MessageType)1, "Entering Build Mode.", 0, (Sprite)null, false);
			}
		}

		internal static bool IsLocalPlayer(Player player)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return (Object)(object)player == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}

		private static bool IsTool(ItemData? itemData)
		{
			return Object.op_Implicit((Object)(object)itemData?.m_shared.m_buildPieces);
		}

		internal static bool ToolIsEquipped(Player player)
		{
			return IsTool(Access.RightItem((Humanoid)(object)player));
		}

		internal static bool ShouldDeactivateBuildMode(Player player)
		{
			return !ToolIsEquipped(player);
		}

		internal static bool BuildStationInRange(Player player)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			CraftingStation station;
			return TryFindCameraStation(((Component)player).transform.position, out station);
		}

		private static bool TryFindCameraStation(Vector3 point, out CraftingStation? station)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			station = null;
			float num = float.MaxValue;
			foreach (CraftingStation allStation in Access.AllStations)
			{
				if (Object.op_Implicit((Object)(object)allStation))
				{
					float num2 = HorizontalDistanceSquared(((Component)allStation).transform.position, point);
					float cameraStationRange = GetCameraStationRange(allStation);
					if (num2 <= cameraStationRange * cameraStationRange && num2 < num)
					{
						station = allStation;
						num = num2;
					}
				}
			}
			return Object.op_Implicit((Object)(object)station);
		}

		internal static CraftingStation? FindCameraStation(string name, Vector3 point)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (CameraStationsByName.TryGetValue(name, out CraftingStation value) && IsCameraStationInRange(value, name, point))
			{
				return value;
			}
			CraftingStation val = null;
			float num = float.MaxValue;
			foreach (CraftingStation allStation in Access.AllStations)
			{
				if (Object.op_Implicit((Object)(object)allStation) && !(allStation.m_name != name))
				{
					float num2 = HorizontalDistanceSquared(((Component)allStation).transform.position, point);
					float cameraStationRange = GetCameraStationRange(allStation);
					if (num2 < cameraStationRange * cameraStationRange && num2 < num)
					{
						val = allStation;
						num = num2;
					}
				}
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				CameraStationsByName[name] = val;
			}
			else
			{
				CameraStationsByName.Remove(name);
			}
			return val;
		}

		private static bool IsCameraStationInRange(CraftingStation station, string name, Vector3 point)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)station) || station.m_name != name)
			{
				return false;
			}
			float cameraStationRange = GetCameraStationRange(station);
			return HorizontalDistanceSquared(((Component)station).transform.position, point) < cameraStationRange * cameraStationRange;
		}

		private static float GetCameraStationRange(CraftingStation station)
		{
			return Mathf.Max(station.GetStationBuildRange(), Plugin.distanceCanBuildFromWorkbench.Value);
		}

		private static float HorizontalDistanceSquared(Vector3 first, Vector3 second)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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)
			float num = first.x - second.x;
			float num2 = first.z - second.z;
			return num * num + num2 * num2;
		}

		private static Vector3 ClampToStationRange(Vector3 position)
		{
			//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)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)_cameraStation))
			{
				DisableBuildMode();
				return position;
			}
			Vector3 position2 = ((Component)_cameraStation).transform.position;
			float num = GetCameraStationRange(_cameraStation) * Plugin.cameraRangeMultiplier.Value;
			Vector3 val = position - position2;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			if (!(sqrMagnitude <= num * num))
			{
				return position2 + val * (num / Mathf.Sqrt(sqrMagnitude));
			}
			return position;
		}

		private static Vector3 ClampToTerrain(Vector3 currentPosition, Vector3 wantedPosition)
		{
			//IL_000b: 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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_00b2: 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_008d: 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)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			float value = Plugin.cameraTerrainClearance.Value;
			Vector3 val = wantedPosition - currentPosition;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			if (sqrMagnitude <= 1E-06f)
			{
				return currentPosition;
			}
			if (Physics.CheckSphere(currentPosition, value, TerrainMask, (QueryTriggerInteraction)1))
			{
				ZoneSystem instance = ZoneSystem.instance;
				if (!Object.op_Implicit((Object)(object)instance) || wantedPosition.y - instance.GetGroundHeight(wantedPosition) >= currentPosition.y - instance.GetGroundHeight(currentPosition))
				{
					return wantedPosition;
				}
				return currentPosition;
			}
			float num = Mathf.Sqrt(sqrMagnitude);
			Vector3 val2 = val / num;
			RaycastHit val3 = default(RaycastHit);
			if (Physics.SphereCast(currentPosition, value, val2, ref val3, num, TerrainMask, (QueryTriggerInteraction)1))
			{
				wantedPosition = currentPosition + val2 * Mathf.Max(0f, ((RaycastHit)(ref val3)).distance - 0.02f);
			}
			if (Physics.CheckSphere(wantedPosition, value, TerrainMask, (QueryTriggerInteraction)1))
			{
				if (_hasLastSafeCameraPosition && !Physics.CheckSphere(_lastSafeCameraPosition, value, TerrainMask, (QueryTriggerInteraction)1))
				{
					return _lastSafeCameraPosition;
				}
				return currentPosition;
			}
			_lastSafeCameraPosition = wantedPosition;
			_hasLastSafeCameraPosition = true;
			return wantedPosition;
		}

		private static Quaternion UpdateBuildCameraViewDirection(float dt)
		{
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			float num = ((Plugin.invertMouseLookHorizontal.Value == Plugin.Toggle.On) ? (-1f) : 1f);
			float num2 = ((Plugin.invertControllerLookHorizontal.Value == Plugin.Toggle.On) ? (-1f) : 1f);
			Plugin.CameraYaw += num * PlayerController.m_mouseSens * Input.GetAxis("Mouse X") + num2 * ZInput.GetJoyRightStickX() * 110f * dt;
			float num3 = (PlayerController.m_invertMouse ? (-1f) : 1f);
			float num4 = ((Plugin.invertMouseLookVertical.Value == Plugin.Toggle.On) ? (0f - num3) : num3);
			float num5 = ((Plugin.invertControllerLookVertical.Value == Plugin.Toggle.On) ? (-1f) : 1f);
			Plugin.CameraPitch = Mathf.Clamp(Plugin.CameraPitch - (num4 * PlayerController.m_mouseSens * Input.GetAxis("Mouse Y") - num5 * ZInput.GetJoyRightStickY() * 110f * dt), -89f, 89f);
			return Quaternion.Euler(0f, Plugin.CameraYaw, 0f) * Quaternion.Euler(Plugin.CameraPitch, 0f, 0f);
		}

		private static Vector3 GetMovementInput(float dt)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: 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_010b: 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)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.zero;
			if (ZInput.GetButton("Left"))
			{
				val -= Vector3.right;
			}
			if (ZInput.GetButton("Right"))
			{
				val += Vector3.right;
			}
			if (ZInput.GetButton("Forward"))
			{
				val += Vector3.forward;
			}
			if (ZInput.GetButton("Backward"))
			{
				val -= Vector3.forward;
			}
			ref float takeInputDelay = ref Access.TakeInputDelay;
			takeInputDelay = Mathf.Max(0f, takeInputDelay - dt);
			if (ZInput.GetButton("Jump") || (ZInput.GetButton("JoyJump") && takeInputDelay <= 0f && !Hud.IsPieceSelectionVisible()))
			{
				val += Vector3.up;
			}
			if (ZInput.GetButton("Crouch") || ZInput.GetButtonPressedTimer("JoyCrouch") > 0.33f)
			{
				val -= Vector3.up;
			}
			((Vector3)(ref val)).Normalize();
			val += Vector3.right * ZInput.GetJoyLeftStickX();
			val -= Vector3.forward * ZInput.GetJoyLeftStickY();
			float num = (ZInput.GetButton("Run") ? ((Character)Player.m_localPlayer).m_runSpeed : ((Character)Player.m_localPlayer).m_walkSpeed);
			return val * (dt * num * Plugin.cameraMoveSpeedMultiplier.Value);
		}

		internal static void UpdateBuildCamera(float dt, GameCamera camera)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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)
			if (!Console.IsVisible() && Access.TakeInput((Character)(object)Player.m_localPlayer) && !Hud.IsPieceSelectionVisible())
			{
				Vector3 val = GetMovementInput(dt);
				Transform transform = ((Component)camera).transform;
				if (Plugin.moveWithRespectToWorld.Value != Plugin.Toggle.On)
				{
					val = transform.TransformVector(val);
				}
				Vector3 wantedPosition = ClampToStationRange(transform.position + val);
				transform.position = ClampToTerrain(transform.position, wantedPosition);
				transform.rotation = UpdateBuildCameraViewDirection(dt);
			}
		}

		private static bool HasRequiredComfort()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer))
			{
				return false;
			}
			if ((Object)(object)localPlayer == (Object)(object)_comfortPlayer && Time.time < _nextComfortRefresh)
			{
				return _hasRequiredComfort;
			}
			_comfortPlayer = localPlayer;
			_nextComfortRefresh = Time.time + 0.2f;
			_hasRequiredComfort = CalculateComfort(localPlayer);
			return _hasRequiredComfort;
		}

		private static bool CalculateComfort(Player player)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if (player.GetComfortLevel() < Plugin.minimumComfortLevel.Value)
			{
				return false;
			}
			SEMan sEMan = ((Character)player).GetSEMan();
			if (sEMan == null)
			{
				return false;
			}
			if (sEMan.HaveStatusEffect(SEMan.s_statusEffectResting))
			{
				return true;
			}
			bool num = sEMan.HaveStatusEffect(SEMan.s_statusEffectCampFire);
			bool flag = player.InShelter() || ((Character)player).IsSitting();
			bool flag2 = Object.op_Implicit((Object)(object)EffectArea.IsPointInsideArea(((Component)player).transform.position, (Type)64, 1f));
			bool flag3 = sEMan.HaveStatusEffect(SEMan.s_statusEffectWet) && !flag2;
			bool flag4 = sEMan.HaveStatusEffect(SEMan.s_statusEffectCold) || sEMan.HaveStatusEffect(SEMan.s_statusEffectFreezing);
			if (num && flag && !player.IsSensed() && !flag3 && !flag4)
			{
				return !sEMan.HaveStatusEffect(SEMan.s_statusEffectBurning);
			}
			return false;
		}

		internal static bool CanUseCamera()
		{
			if (Plugin.restrictionMode.Value == Plugin.RestrictionMode.CameraNeedsCoziness)
			{
				return HasRequiredComfort();
			}
			return true;
		}

		internal static bool CanPickUpFromCamera()
		{
			if (Plugin.restrictionMode.Value == Plugin.RestrictionMode.CameraPickUpNeedsCoziness)
			{
				return HasRequiredComfort();
			}
			return true;
		}

		internal static void ShowComfortMessage()
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && !(Time.time < _nextComfortMessageTime))
			{
				_nextComfortMessageTime = Time.time + 1.5f;
				string text = Localization.instance.Localize("$shackmagiccam_needs_cozy", new string[1] { Plugin.minimumComfortLevel.Value.ToString() });
				((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}

		internal static bool ShouldShowPickupWarning()
		{
			if (InBuildMode() && !CanPickUpFromCamera())
			{
				return HasNearbyPickup();
			}
			return false;
		}

		private static bool HasNearbyPickup()
		{
			//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_002e: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)GameCamera.instance) || !Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return false;
			}
			int num = Physics.OverlapSphereNonAlloc(((Component)GameCamera.instance).transform.position + Vector3.up, Plugin.resourcePickupRange.Value, NearbyPickupColliders, Access.AutoPickupMask(Player.m_localPlayer));
			try
			{
				for (int i = 0; i < num; i++)
				{
					if (TryFindItemDrop(NearbyPickupColliders[i], out ItemDrop item) && item.m_autoPickup && !item.IsPiece())
					{
						return true;
					}
				}
				return false;
			}
			finally
			{
				Array.Clear(NearbyPickupColliders, 0, num);
			}
		}

		internal static bool TryGetAutoPickupPlayer(out Player player)
		{
			player = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)player) && !((Character)player).IsTeleporting() && Access.EnableAutoPickup)
			{
				return CanPickUpFromCamera();
			}
			return false;
		}

		internal static void AutoPickup(GameCamera camera, Player player)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.OverlapSphereNonAlloc(((Component)camera).transform.position + Vector3.up, Plugin.resourcePickupRange.Value, NearbyPickupColliders, Access.AutoPickupMask(player));
			NearbyPickupItemIds.Clear();
			Inventory inventory = ((Humanoid)player).GetInventory();
			try
			{
				for (int i = 0; i < num; i++)
				{
					if (!TryFindItemDrop(NearbyPickupColliders[i], out ItemDrop item) || !item.m_autoPickup || item.IsPiece() || ((Humanoid)player).HaveUniqueKey(item.m_itemData.m_shared.m_name) || !NearbyPickupItemIds.Add(((Object)item).GetInstanceID()))
					{
						continue;
					}
					ZNetView val = Access.ItemNetView(item);
					if (!Object.op_Implicit((Object)(object)val) || !val.IsValid())
					{
						continue;
					}
					if (!item.CanPickup(true))
					{
						item.RequestOwn();
					}
					else if (!item.InTar())
					{
						item.Load();
						if (inventory.CanAddItem(item.m_itemData, -1) && !(item.m_itemData.GetWeight(-1) + inventory.GetTotalWeight() > player.GetMaxCarryWeight()))
						{
							((Humanoid)player).Pickup(((Component)item).gameObject, true, true);
						}
					}
				}
			}
			finally
			{
				Array.Clear(NearbyPickupColliders, 0, num);
				NearbyPickupItemIds.Clear();
			}
		}

		private static bool TryFindItemDrop(Collider collider, out ItemDrop item)
		{
			item = null;
			if (!Object.op_Implicit((Object)(object)collider) || !Object.op_Implicit((Object)(object)collider.attachedRigidbody))
			{
				return false;
			}
			Rigidbody attachedRigidbody = collider.attachedRigidbody;
			item = ((Component)attachedRigidbody).GetComponent<ItemDrop>();
			if (Object.op_Implicit((Object)(object)item))
			{
				return true;
			}
			FloatingTerrainDummy component = ((Component)attachedRigidbody).GetComponent<FloatingTerrainDummy>();
			if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.m_parent))
			{
				return false;
			}
			item = ((Component)component.m_parent).GetComponent<ItemDrop>();
			return Object.op_Implicit((Object)(object)item);
		}

		internal static void AddLocalizations(Localization localization)
		{
			Access.AddWord(localization, "shackmagiccam_needs_cozy", "Be cozy to use the build camera (requires comfort $1).");
			Access.AddWord(localization, "shackmagiccam_pickup_blocked_title", "Build Camera Pickup");
			Access.AddWord(localization, "shackmagiccam_pickup_blocked", "Get cozy before collecting items through the build camera.\nRequired comfort: $1");
		}
	}
}
namespace TheShack.MagicCam.Compatibility.WardIsLove
{
	internal static class WardAccess
	{
		private delegate bool CheckAccessHandler(long playerId, Vector3 point, float radius, bool flash);

		private const string PluginGuid = "Azumatt.WardIsLove";

		private static readonly Version MinimumVersion = new Version(2, 3, 3);

		private static readonly bool WardIsLoveLoaded = Chainloader.PluginInfos.TryGetValue("Azumatt.WardIsLove", out var value) && value.Metadata.Version.CompareTo(MinimumVersion) >= 0;

		private static readonly CheckAccessHandler? WardIsLoveCheck = (WardIsLoveLoaded ? ResolveWardIsLoveCheck() : null);

		private static bool _warnedAboutMissingCheck;

		internal static bool Check(long playerId, Vector3 point)
		{
			//IL_000d: 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)
			if (WardIsLoveCheck != null)
			{
				return WardIsLoveCheck(playerId, point, 0f, flash: false);
			}
			if (WardIsLoveLoaded && !_warnedAboutMissingCheck)
			{
				_warnedAboutMissingCheck = true;
				Plugin.Log.LogWarning((object)"Azumatt.WardIsLove is loaded but WardIsLove.Util.CustomCheck.CheckAccess could not be resolved - falling back to the vanilla ward check.");
			}
			return PrivateArea.CheckAccess(point, 0f, false, true);
		}

		private static CheckAccessHandler? ResolveWardIsLoveCheck()
		{
			try
			{
				MethodInfo methodInfo = Type.GetType("WardIsLove.Util.CustomCheck, WardIsLove", throwOnError: false)?.GetMethod("CheckAccess", BindingFlags.Static | BindingFlags.Public, null, new Type[4]
				{
					typeof(long),
					typeof(Vector3),
					typeof(float),
					typeof(bool)
				}, null);
				return (methodInfo == null) ? null : ((CheckAccessHandler)Delegate.CreateDelegate(typeof(CheckAccessHandler), methodInfo));
			}
			catch
			{
				return null;
			}
		}
	}
}