Decompiled source of Build Camera Custom Hammers Edition v1.3.2

Build Camera.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using Valheim_Build_Camera.Compatibility.WardIsLove;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Custom Hammers Edition")]
[assembly: AssemblyDescription("Support for Custom Hammers")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Azumatt/Gittywithexcitement")]
[assembly: AssemblyProduct("Custom Hammers Edition")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("28173031-3a88-4e18-835e-9cbd815f0588")]
[assembly: AssemblyFileVersion("1.3.2")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.2.0")]
[module: UnverifiableCode]
[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 Valheim_Build_Camera
{
	[BepInPlugin("Azumatt.BuildCameraCHE", "BuildCameraCHE", "1.3.2")]
	public class Valheim_Build_CameraPlugin : 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 = "BuildCameraCHE";

		internal const string ModVersion = "1.3.2";

		internal const string Author = "Azumatt";

		private const string ModGUID = "Azumatt.BuildCameraCHE";

		private readonly Harmony _harmony = new Harmony("Azumatt.BuildCameraCHE");

		private FileSystemWatcher? _configWatcher;

		private static readonly string ConfigFileName = "Azumatt.BuildCameraCHE.cfg";

		private static readonly string ConfigFileFullPath;

		internal static string ConnectionError;

		public static readonly ManualLogSource BuildCameraCHELogger;

		private static readonly ConfigSync ConfigSync;

		internal static bool BuildCameraActive;

		internal static float CameraYaw;

		internal static float CameraPitch;

		private static ConfigEntry<Toggle> _serverConfigLocked;

		internal static ConfigEntry<float> distanceCanBuildFromAvatar;

		internal static ConfigEntry<float> distanceCanBuildFromWorkbench;

		internal static ConfigEntry<float> resourcePickupRange;

		internal static ConfigEntry<float> cameraRangeMultiplier;

		internal static ConfigEntry<float> cameraMoveSpeedMultiplier;

		internal static ConfigEntry<float> cameraTerrainClearance;

		internal static ConfigEntry<RestrictionMode> restrictionMode;

		internal static ConfigEntry<int> minimumComfortLevel;

		internal static ConfigEntry<Toggle> moveWithRespectToWorld;

		internal static ConfigEntry<KeyboardShortcut> toggleBuildMode;

		internal static ConfigEntry<Toggle> verboseLogging;

		internal static ConfigEntry<Toggle> demisterFollowCamera;

		internal static ConfigEntry<float> demisterRangeMultiplier;

		internal static ConfigEntry<Toggle> followDvergrCircletLight;

		internal static ConfigEntry<float> helmetLightOffsetForward;

		internal static ConfigEntry<float> helmetLightOffsetUp;

		internal static ConfigEntry<float> helmetLightOffsetRight;

		internal static ConfigEntry<float> helmetLightIntensityMultiplier;

		internal static ConfigEntry<float> helmetLightRangeMultiplier;

		internal static ConfigEntry<string> helmetLightColor;

		internal static ConfigEntry<CameraLightShadows> helmetLightShadows;

		internal static ConfigEntry<float> pickupHudX;

		internal static ConfigEntry<float> pickupHudY;

		internal static ConfigEntry<int> pickupHudFontSize;

		internal static ConfigEntry<Toggle> invertControllerLookHorizontal;

		internal static ConfigEntry<Toggle> invertControllerLookVertical;

		internal static ConfigEntry<Toggle> invertMouseLookHorizontal;

		internal static ConfigEntry<Toggle> invertMouseLookVertical;

		private void Awake()
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Expected O, but got Unknown
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Expected O, but got Unknown
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Expected O, but got Unknown
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Expected O, but got Unknown
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Expected O, but got Unknown
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Expected O, but got Unknown
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Expected O, but got Unknown
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fc: Expected O, but got Unknown
			_serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only.");
			ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked);
			distanceCanBuildFromAvatar = config("General", "Distance Can Build From Avatar", 100f, "Distance from your avatar that you can build or repair. (Valheim default is 8)");
			distanceCanBuildFromWorkbench = config("General", "Distance Can Build From Workbench", 100f, "Maximum distance between the build camera and its workbench/stonecutter/etc. This does not change the station's actual build or player-base radius.");
			resourcePickupRange = config("General", "Resource Pickup Range", 10f, "Distance from which you can pick up resources on the ground while in build mode. (Valheim default is 2)");
			cameraRangeMultiplier = config("General", "Camera Range Multiplier", 1f, "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.");
			cameraMoveSpeedMultiplier = config("General", "Camera Move Speed Multiplier", 3f, "Multiplies the speed at which the build camera pans (i.e. moves around).");
			cameraTerrainClearance = config("General", "Camera Terrain Clearance", 0f, new ConfigDescription("Radius kept clear around the detached camera so it cannot cross terrain or a HearthBelow cave wall. 0 turns the clamp off entirely and lets the camera pass through terrain.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 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)98, 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 = B + 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", 2.5f, "Multiplier for the demister's mist-clearing range while in build mode. Higher values clear more mist. (Default: 2.5x, Vanilla: 1.0x)");
			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);
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			_harmony.PatchAll(executingAssembly);
			Utils.AddLocalizations(Localization.instance);
			SetupWatcher();
		}

		private void Update()
		{
			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
			{
				BuildCameraCHELogger.LogDebug((object)"ReadConfigValues called");
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch
			{
				BuildCameraCHELogger.LogError((object)("There was an issue loading your " + ConfigFileName));
				BuildCameraCHELogger.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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting;
			return val2;
		}

		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);
		}

		static Valheim_Build_CameraPlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
			ConnectionError = "";
			BuildCameraCHELogger = Logger.CreateLogSource("BuildCameraCHE");
			ConfigSync = new ConfigSync("Azumatt.BuildCameraCHE")
			{
				DisplayName = "BuildCameraCHE",
				CurrentVersion = "1.3.2",
				MinimumRequiredVersion = "1.3.2"
			};
			_serverConfigLocked = null;
			distanceCanBuildFromAvatar = null;
			distanceCanBuildFromWorkbench = null;
			resourcePickupRange = null;
			cameraRangeMultiplier = null;
			cameraMoveSpeedMultiplier = null;
			cameraTerrainClearance = null;
			restrictionMode = null;
			minimumComfortLevel = null;
			moveWithRespectToWorld = null;
			toggleBuildMode = null;
			verboseLogging = null;
			demisterFollowCamera = null;
			demisterRangeMultiplier = null;
			followDvergrCircletLight = null;
			helmetLightOffsetForward = null;
			helmetLightOffsetUp = null;
			helmetLightOffsetRight = null;
			helmetLightIntensityMultiplier = null;
			helmetLightRangeMultiplier = null;
			helmetLightColor = null;
			helmetLightShadows = null;
			pickupHudX = null;
			pickupHudY = null;
			pickupHudFontSize = null;
			invertControllerLookHorizontal = null;
			invertControllerLookVertical = null;
			invertMouseLookHorizontal = null;
			invertMouseLookVertical = null;
		}
	}
	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;
					Valheim_Build_CameraPlugin.BuildCameraCHELogger.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) || Valheim_Build_CameraPlugin.followDvergrCircletLight.Value != Valheim_Build_CameraPlugin.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 * Valheim_Build_CameraPlugin.helmetLightOffsetUp.Value;
			val += transform.forward * Valheim_Build_CameraPlugin.helmetLightOffsetForward.Value;
			val += transform.right * Valheim_Build_CameraPlugin.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 = ((Humanoid)player).m_visEquipment;
			if (Object.op_Implicit((Object)(object)visEquipment))
			{
				if (IsDvergrCirclet(((Humanoid)player).m_helmetItem) && Object.op_Implicit((Object)(object)visEquipment.m_helmetItemInstance))
				{
					AddCircletLights(visEquipment.m_helmetItemInstance);
				}
				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("BuildCamera_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 * Valheim_Build_CameraPlugin.helmetLightIntensityMultiplier.Value;
			copiedLight.range = sourceLight.range * Valheim_Build_CameraPlugin.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 = Valheim_Build_CameraPlugin.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)(Valheim_Build_CameraPlugin.helmetLightShadows.Value switch
			{
				Valheim_Build_CameraPlugin.CameraLightShadows.Off => 0, 
				Valheim_Build_CameraPlugin.CameraLightShadows.Hard => 1, 
				Valheim_Build_CameraPlugin.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, Valheim_Build_CameraPlugin.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), "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 void Prefix(Player __instance, ref bool __runOriginal)
		{
			if (!Utils.IsLocalPlayer(in __instance) || !Utils.InBuildMode())
			{
				__runOriginal = true;
				return;
			}
			if (!Utils.CanUseCamera())
			{
				Utils.ShowComfortMessage();
				Utils.DisableBuildMode();
				__runOriginal = true;
				return;
			}
			if (Utils.ShouldDeactivateBuildMode(in __instance))
			{
				Utils.DisableBuildMode();
				__runOriginal = true;
				return;
			}
			__runOriginal = false;
			if (!((Character)__instance).TakeInput())
			{
				return;
			}
			for (int i = 0; i < HotbarButtons.Length; i++)
			{
				if (Input.GetKeyDown((KeyCode)(49 + i)) || ZInput.GetButtonDown(HotbarButtons[i]))
				{
					__instance.UseHotbarItem(i + 1);
				}
			}
			if ((ZInput.GetButtonDown("Hide") || ZInput.GetButtonDown("JoyHide")) && (((Humanoid)__instance).GetRightItem() != null || ((Humanoid)__instance).GetLeftItem() != null) && !((Character)__instance).InAttack())
			{
				((Humanoid)__instance).HideHandItems(false, true);
			}
			__instance.UpdatePlacement(true, Time.deltaTime);
		}

		private static void Postfix(Player __instance)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!Utils.IsLocalPlayer(in __instance))
			{
				return;
			}
			KeyboardShortcut value = Valheim_Build_CameraPlugin.toggleBuildMode.Value;
			if (!((KeyboardShortcut)(ref value)).IsDown())
			{
				return;
			}
			if (Utils.InBuildMode())
			{
				if (((Character)__instance).TakeInput())
				{
					Utils.DisableBuildMode();
				}
			}
			else if (!((Character)__instance).TakeInput())
			{
				Utils.LogWhenVerbose("Build Mode not enabled because chat, console, menu, inventory, map, or similar is open.");
			}
			else if (!Utils.ToolIsEquipped(in __instance))
			{
				Utils.LogWhenVerbose("Build Mode not enabled because hammer is not equipped.");
			}
			else if (!Utils.BuildStationInRange(in __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
			{
				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())
			{
				__runOriginal = true;
				return;
			}
			__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_004d: Unknown result type (might be due to invalid IL or missing references)
			if (!Utils.InBuildMode())
			{
				_nextPickupScan = 0f;
				__runOriginal = true;
				return;
			}
			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("BuildCamera_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_0082: 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
			{
				((Graphic)background).color = new Color(0.06f, 0.055f, 0.045f, 0.92f);
			}
		}

		private static bool NeedsRefresh()
		{
			if (_lastComfortLevel != Valheim_Build_CameraPlugin.minimumComfortLevel.Value)
			{
				return true;
			}
			if (_lastFontSize != Valheim_Build_CameraPlugin.pickupHudFontSize.Value)
			{
				return true;
			}
			if (!Mathf.Approximately(_lastHudX, Valheim_Build_CameraPlugin.pickupHudX.Value))
			{
				return true;
			}
			return !Mathf.Approximately(_lastHudY, Valheim_Build_CameraPlugin.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 = Valheim_Build_CameraPlugin.minimumComfortLevel.Value;
			_lastFontSize = Valheim_Build_CameraPlugin.pickupHudFontSize.Value;
			_lastHudX = Valheim_Build_CameraPlugin.pickupHudX.Value;
			_lastHudY = Valheim_Build_CameraPlugin.pickupHudY.Value;
			((TMP_Text)_titleText).text = Localization.instance.Localize("$buildcamera_pickup_blocked_title");
			((TMP_Text)_bodyText).text = Localization.instance.Localize("$buildcamera_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);
			}
		}
	}
	[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 player = (Player)(object)((character is Player) ? character : null);
			GameCamera instance = GameCamera.instance;
			if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)instance) || !Utils.IsLocalPlayer(in player) || !Utils.InBuildMode() || Valheim_Build_CameraPlugin.demisterFollowCamera.Value != Valheim_Build_CameraPlugin.Toggle.On)
			{
				RestoreNormalForceField();
				return true;
			}
			UpdateForceFieldRange(__instance);
			UpdateDemisterForCamera(__instance, player, ((Component)instance).transform, dt);
			return false;
		}

		private static void UpdateForceFieldRange(SE_Demister instance)
		{
			GameObject ballInstance = instance.m_ballInstance;
			if (!Object.op_Implicit((Object)(object)ballInstance))
			{
				return;
			}
			if ((Object)(object)_trackedBall != (Object)(object)ballInstance || !Object.op_Implicit((Object)(object)_trackedForceField))
			{
				RestoreNormalForceField();
				ParticleSystemForceField componentInChildren = ballInstance.GetComponentInChildren<ParticleSystemForceField>();
				if (!Object.op_Implicit((Object)(object)componentInChildren))
				{
					return;
				}
				_trackedBall = ballInstance;
				_trackedForceField = componentInChildren;
				_originalForceFieldRange = componentInChildren.endRange;
			}
			_trackedForceField.endRange = _originalForceFieldRange * Valheim_Build_CameraPlugin.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_0044: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_0084: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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_0104: 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_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: 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_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: 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_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: 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_0154: 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_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: 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_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = camera.position;
			Vector3 forward = camera.forward;
			if (!Object.op_Implicit((Object)(object)instance.m_ballInstance))
			{
				instance.m_ballInstance = Object.Instantiate<GameObject>(instance.m_ballPrefab, position + forward * 0.5f, Quaternion.identity);
				return;
			}
			bool num = IsUnderRoof(instance, position);
			Transform transform = instance.m_ballInstance.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)
			{
				instance.m_ballVel += val7 * (instance.m_ballAcceleration * dt / Mathf.Sqrt(sqrMagnitude2));
			}
			float sqrMagnitude3 = ((Vector3)(ref instance.m_ballVel)).sqrMagnitude;
			float num5 = instance.m_ballMaxSpeed * instance.m_ballMaxSpeed;
			if (sqrMagnitude3 > num5)
			{
				instance.m_ballVel *= instance.m_ballMaxSpeed / Mathf.Sqrt(sqrMagnitude3);
			}
			if (!num)
			{
				instance.m_ballVel += ((Character)player).GetVelocity() * instance.m_characterVelocityFactor * dt;
			}
			instance.m_ballVel -= instance.m_ballVel * instance.m_ballFriction;
			transform.position = val + instance.m_ballVel * 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, instance.m_coverRayMask);
		}

		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(__instance.m_ballInstance);
		}
	}
	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 static readonly MethodInfo AddWordMethod = AccessTools.Method(typeof(Localization), "AddWord", new Type[2]
		{
			typeof(string),
			typeof(string)
		}, (Type[])null);

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

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

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

		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_0045: 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)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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))
			{
				Valheim_Build_CameraPlugin.BuildCameraActive = true;
				Quaternion rotation = ((Component)((Character)Player.m_localPlayer).m_eye).transform.rotation;
				Valheim_Build_CameraPlugin.CameraPitch = ((Quaternion)(ref rotation)).eulerAngles.x;
				Valheim_Build_CameraPlugin.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(in 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(in ItemData itemData)
		{
			return Object.op_Implicit((Object)(object)itemData?.m_shared.m_buildPieces);
		}

		internal static bool ToolIsEquipped(in Player player)
		{
			return IsTool(in ((Humanoid)player).m_rightItem);
		}

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

		internal static bool BuildStationInRange(in Player player)
		{
			//IL_0007: 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 CraftingStation.m_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 CraftingStation.m_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(), Valheim_Build_CameraPlugin.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) * Valheim_Build_CameraPlugin.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_0015: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0036: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			float value = Valheim_Build_CameraPlugin.cameraTerrainClearance.Value;
			if (value <= 0f)
			{
				return wantedPosition;
			}
			Vector3 val = wantedPosition - currentPosition;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			if (sqrMagnitude <= 1E-06f)
			{
				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 = ((Valheim_Build_CameraPlugin.invertMouseLookHorizontal.Value == Valheim_Build_CameraPlugin.Toggle.On) ? (-1f) : 1f);
			float num2 = ((Valheim_Build_CameraPlugin.invertControllerLookHorizontal.Value == Valheim_Build_CameraPlugin.Toggle.On) ? (-1f) : 1f);
			Valheim_Build_CameraPlugin.CameraYaw += num * PlayerController.m_mouseSens * Input.GetAxis("Mouse X") + num2 * ZInput.GetJoyRightStickX() * 110f * dt;
			float num3 = (PlayerController.m_invertMouse ? (-1f) : 1f);
			float num4 = ((Valheim_Build_CameraPlugin.invertMouseLookVertical.Value == Valheim_Build_CameraPlugin.Toggle.On) ? (0f - num3) : num3);
			float num5 = ((Valheim_Build_CameraPlugin.invertControllerLookVertical.Value == Valheim_Build_CameraPlugin.Toggle.On) ? (-1f) : 1f);
			Valheim_Build_CameraPlugin.CameraPitch = Mathf.Clamp(Valheim_Build_CameraPlugin.CameraPitch - (num4 * PlayerController.m_mouseSens * Input.GetAxis("Mouse Y") - num5 * ZInput.GetJoyRightStickY() * 110f * dt), -89f, 89f);
			return Quaternion.Euler(0f, Valheim_Build_CameraPlugin.CameraYaw, 0f) * Quaternion.Euler(Valheim_Build_CameraPlugin.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_00a7: 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_00b2: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: 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)
			//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_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: 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)
			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;
			}
			Character.takeInputDelay = Mathf.Max(0f, Character.takeInputDelay - dt);
			if (ZInput.GetButton("Jump") || (ZInput.GetButton("JoyJump") && Character.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 * Valheim_Build_CameraPlugin.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() && ((Character)Player.m_localPlayer).TakeInput() && !Hud.IsPieceSelectionVisible())
			{
				Vector3 val = GetMovementInput(dt);
				Transform transform = ((Component)camera).transform;
				if (Valheim_Build_CameraPlugin.moveWithRespectToWorld.Value != Valheim_Build_CameraPlugin.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() < Valheim_Build_CameraPlugin.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 (Valheim_Build_CameraPlugin.restrictionMode.Value == Valheim_Build_CameraPlugin.RestrictionMode.CameraNeedsCoziness)
			{
				return HasRequiredComfort();
			}
			return true;
		}

		internal static bool CanPickUpFromCamera()
		{
			if (Valheim_Build_CameraPlugin.restrictionMode.Value == Valheim_Build_CameraPlugin.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("$buildcamera_needs_cozy", new string[1] { Valheim_Build_CameraPlugin.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, Valheim_Build_CameraPlugin.resourcePickupRange.Value, NearbyPickupColliders, Player.m_localPlayer.m_autoPickupMask);
			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() && Player.m_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, Valheim_Build_CameraPlugin.resourcePickupRange.Value, NearbyPickupColliders, player.m_autoPickupMask);
			NearbyPickupItemIds.Clear();
			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 nview = item.m_nview;
					if (!Object.op_Implicit((Object)(object)nview) || !nview.IsValid())
					{
						continue;
					}
					if (!item.CanPickup(true))
					{
						item.RequestOwn();
					}
					else if (!item.InTar())
					{
						item.Load();
						if (((Humanoid)player).m_inventory.CanAddItem(item.m_itemData, -1) && !(item.m_itemData.GetWeight(-1) + ((Humanoid)player).m_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);
		}

		private static void AddWord(Localization localization, string key, string text)
		{
			AddWordMethod?.Invoke(localization, new object[2] { key, text });
		}

		internal static void AddLocalizations(Localization localization)
		{
			AddWord(localization, "buildcamera_needs_cozy", "Be cozy to use Build Camera (requires comfort $1).");
			AddWord(localization, "buildcamera_pickup_blocked_title", "Build Camera Pickup");
			AddWord(localization, "buildcamera_pickup_blocked", "Get cozy before collecting items through the build camera.\nRequired comfort: $1");
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
	internal static class RegisterAndCheckVersion
	{
		private static void Prefix(ZNetPeer peer)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			Valheim_Build_CameraPlugin.BuildCameraCHELogger.LogDebug((object)"Registering version RPC handler");
			peer.m_rpc.Register<ZPackage>("BuildCameraCHE_VersionCheck", (Action<ZRpc, ZPackage>)RpcHandlers.ReceiveVersion);
			Valheim_Build_CameraPlugin.BuildCameraCHELogger.LogInfo((object)"Invoking version check");
			ZPackage val = new ZPackage();
			val.Write("1.3.2");
			peer.m_rpc.Invoke("BuildCameraCHE_VersionCheck", new object[1] { val });
		}
	}
	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	internal static class VerifyClient
	{
		private static bool Prefix(ZRpc rpc, ZNet __instance)
		{
			if (!__instance.IsServer() || RpcHandlers.ValidatedPeers.Contains(rpc))
			{
				return true;
			}
			Valheim_Build_CameraPlugin.BuildCameraCHELogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") never sent version or couldn't due to previous disconnect, disconnecting"));
			rpc.Invoke("Error", new object[1] { 3 });
			return false;
		}

		private static void Postfix()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.instance.GetServerPeerID(), "BuildCameraCHE_RequestAdminSync", new object[1] { (object)new ZPackage() });
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "ShowConnectError")]
	internal static class ShowConnectionError
	{
		private static void Postfix(FejdStartup __instance)
		{
			if (__instance.m_connectionFailedPanel.activeSelf && !string.IsNullOrEmpty(Valheim_Build_CameraPlugin.ConnectionError))
			{
				TMP_Text connectionFailedError = __instance.m_connectionFailedError;
				connectionFailedError.text = connectionFailedError.text + "\n" + Valheim_Build_CameraPlugin.ConnectionError;
				Valheim_Build_CameraPlugin.ConnectionError = "";
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Disconnect")]
	internal static class RemoveDisconnectedPeerFromVerified
	{
		private static void Prefix(ZNetPeer peer, ZNet __instance)
		{
			if (__instance.IsServer())
			{
				Valheim_Build_CameraPlugin.BuildCameraCHELogger.LogInfo((object)("Peer (" + peer.m_rpc.m_socket.GetHostName() + ") disconnected, removing from validated list"));
				RpcHandlers.ValidatedPeers.Remove(peer.m_rpc);
			}
		}
	}
	[HarmonyPatch]
	internal static class ClearValidatedPeersOnShutdown
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.DeclaredMethod(typeof(ZNet), "Shutdown", (Type[])null, (Type[])null);
			yield return AccessTools.DeclaredMethod(typeof(ZNet), "ShutdownWithoutSave", (Type[])null, (Type[])null);
		}

		private static void Prefix()
		{
			RpcHandlers.ValidatedPeers.Clear();
		}
	}
	internal static class RpcHandlers
	{
		internal const string VersionCheckRpc = "BuildCameraCHE_VersionCheck";

		internal const string RequestAdminSyncRpc = "BuildCameraCHE_RequestAdminSync";

		internal static readonly HashSet<ZRpc> ValidatedPeers = new HashSet<ZRpc>();

		internal static void ReceiveVersion(ZRpc rpc, ZPackage pkg)
		{
			string text = pkg.ReadString();
			Valheim_Build_CameraPlugin.BuildCameraCHELogger.LogInfo((object)("Version check, local: 1.3.2,  remote: " + text));
			if (text != "1.3.2")
			{
				if (!ZNet.instance.IsServer())
				{
					Valheim_Build_CameraPlugin.ConnectionError = "BuildCameraCHE Installed: 1.3.2\n Needed: " + text;
					return;
				}
				Valheim_Build_CameraPlugin.BuildCameraCHELogger.LogWarning((object)("Peer (" + rpc.m_socket.GetHostName() + ") has incompatible version, disconnecting"));
				rpc.Invoke("Error", new object[1] { 3 });
			}
			else if (!ZNet.instance.IsServer())
			{
				Valheim_Build_CameraPlugin.ConnectionError = "";
				Valheim_Build_CameraPlugin.BuildCameraCHELogger.LogInfo((object)"Received same version from server!");
			}
			else
			{
				Valheim_Build_CameraPlugin.BuildCameraCHELogger.LogInfo((object)("Adding peer (" + rpc.m_socket.GetHostName() + ") to validated list"));
				ValidatedPeers.Add(rpc);
			}
		}
	}
}
namespace Valheim_Build_Camera.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);

		internal static bool Check(long playerId, Vector3 point)
		{
			//IL_0007: 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)
			if (!WardIsLoveLoaded)
			{
				return PrivateArea.CheckAccess(point, 0f, false, true);
			}
			return WardIsLoveCheck?.Invoke(playerId, point, 0f, flash: false) ?? false;
		}

		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;
			}
		}
	}
}
namespace ServerSync
{
	[PublicAPI]
	internal abstract class OwnConfigEntryBase
	{
		public object? LocalBaseValue;

		public bool SynchronizedConfig = true;

		public abstract ConfigEntryBase BaseConfig { get; }
	}
	[PublicAPI]
	internal class SyncedConfigEntry<T>(ConfigEntry<T> sourceConfig) : OwnConfigEntryBase()
	{
		public readonly ConfigEntry<T> SourceConfig = sourceConfig;

		public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig;

		public T Value
		{
			get
			{
				return SourceConfig.Value;
			}
			set
			{
				SourceConfig.Value = value;
			}
		}

		public void AssignLocalValue(T value)
		{
			if (LocalBaseValue == null)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal abstract class CustomSyncedValueBase
	{
		public object? LocalBaseValue;

		public readonly string Identifier;

		public readonly Type Type;

		private object? boxedValue;

		protected bool localIsOwner;

		public readonly int Priority;

		public object? BoxedValue
		{
			get
			{
				return boxedValue;
			}
			set
			{
				boxedValue = value;
				this.ValueChanged?.Invoke();
			}
		}

		public event Action? ValueChanged;

		protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority)
		{
			Priority = priority;
			Identifier = identifier;
			Type = type;
			configSync.AddCustomValue(this);
			localIsOwner = configSync.IsSourceOfTruth;
			configSync.SourceOfTruthChanged += delegate(bool truth)
			{
				localIsOwner = truth;
			};
		}
	}
	[PublicAPI]
	internal sealed class CustomSyncedValue<T> : CustomSyncedValueBase
	{
		public T Value
		{
			get
			{
				return (T)base.BoxedValue;
			}
			set
			{
				base.BoxedValue = value;
			}
		}

		public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0)
			: base(configSync, identifier, typeof(T), priority)
		{
			Value = value;
		}

		public void AssignLocalValue(T value)
		{
			if (localIsOwner)
			{
				Value = value;
			}
			else
			{
				LocalBaseValue = value;
			}
		}
	}
	internal class ConfigurationManagerAttributes
	{
		[UsedImplicitly]
		public bool? ReadOnly = false;
	}
	[PublicAPI]
	internal class ConfigSync
	{
		[HarmonyPatch(typeof(ZRpc), "HandlePackage")]
		private static class SnatchCurrentlyHandlingRPC
		{
			public static ZRpc? currentRpc;

			[HarmonyPrefix]
			private static void Prefix(ZRpc __instance)
			{
				currentRpc = __instance;
			}
		}

		[HarmonyPatch(typeof(ZNet), "Awake")]
		internal static class RegisterRPCPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance)
			{
				isServer = __instance.IsServer();
				foreach (ConfigSync configSync2 in configSyncs)
				{
					ZRoutedRpc.instance.Register<ZPackage>(configSync2.Name + " ConfigSync", (Action<long, ZPackage>)configSync2.RPC_FromOtherClientConfigSync);
					if (isServer)
					{
						configSync2.InitialSyncDone = true;
						Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections"));
					}
				}
				if (isServer)
				{
					((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges());
				}
				static void SendAdmin(List<ZNetPeer> peers, bool isAdmin)
				{
					ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1]
					{
						new PackageEntry
						{
							section = "Internal",
							key = "lockexempt",
							type = typeof(bool),
							value = isAdmin
						}
					});
					ConfigSync configSync = configSyncs.First();
					if (configSync != null)
					{
						((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package));
					}
				}
				static IEnumerator WatchAdminListChanges()
				{
					MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null);
					SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance);
					List<string> CurrentList = new List<string>(adminList.GetList());
					while (true)
					{
						yield return (object)new WaitForSeconds(30f);
						if (!adminList.GetList().SequenceEqual(CurrentList))
						{
							CurrentList = new List<string>(adminList.GetList());
							List<ZNetPeer> adminPeer = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p)
							{
								string hostName = p.m_rpc.GetSocket().GetHostName();
								return ((object)listContainsId == null) ? adminList.Contains(hostName) : ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName }));
							}).ToList();
							List<ZNetPeer> nonAdminPeer = ZNet.instance.GetPeers().Except(adminPeer).ToList();
							SendAdmin(nonAdminPeer, isAdmin: false);
							SendAdmin(adminPeer, isAdmin: true);
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		private static class RegisterClientRPCPatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance, ZNetPeer peer)
			{
				if (__instance.IsServer())
				{
					return;
				}
				foreach (ConfigSync configSync in configSyncs)
				{
					peer.m_rpc.Register<ZPackage>(configSync.Name + " ConfigSync", (Action<ZRpc, ZPackage>)configSync.RPC_FromServerConfigSync);
				}
			}
		}

		private class ParsedConfigs
		{
			public readonly Dictionary<OwnConfigEntryBase, object?> configValues = new Dictionary<OwnConfigEntryBase, object>();

			public readonly Dictionary<CustomSyncedValueBase, object?> customValues = new Dictionary<CustomSyncedValueBase, object>();
		}

		[HarmonyPatch(typeof(ZNet), "Shutdown")]
		private class ResetConfigsOnShutdown
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				ProcessingServerUpdate = true;
				foreach (ConfigSync configSync in configSyncs)
				{
					configSync.resetConfigsFromServer();
					configSync.IsSourceOfTruth = true;
					configSync.InitialSyncDone = false;
				}
				ProcessingServerUpdate = false;
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		private class SendConfigsAfterLogin
		{
			private class BufferingSocket : ZPlayFabSocket, ISocket
			{
				public volatile bool finished = false;

				public volatile int versionMatchQueued = -1;

				public readonly List<ZPackage> Package = new List<ZPackage>();

				public readonly ISocket Original;

				public BufferingSocket(ISocket original)
				{
					Original = original;
					((ZPlayFabSocket)this)..ctor();
				}

				public bool IsConnected()
				{
					return Original.IsConnected();
				}

				public ZPackage Recv()
				{
					return Original.Recv();
				}

				public int GetSendQueueSize()
				{
					return Original.GetSendQueueSize();
				}

				public int GetCurrentSendRate()
				{
					return Original.GetCurrentSendRate();
				}

				public bool IsHost()
				{
					return Original.IsHost();
				}

				public void Dispose()
				{
					Original.Dispose();
				}

				public bool GotNewData()
				{
					return Original.GotNewData();
				}

				public void Close()
				{
					Original.Close();
				}

				public string GetEndPointString()
				{
					return Original.GetEndPointString();
				}

				public void GetAndResetStats(out int totalSent, out int totalRecv)
				{
					Original.GetAndResetStats(ref totalSent, ref totalRecv);
				}

				public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec)
				{
					Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec);
				}

				public ISocket Accept()
				{
					return Original.Accept();
				}

				public int GetHostPort()
				{
					return Original.GetHostPort();
				}

				public bool Flush()
				{
					return Original.Flush();
				}

				public string GetHostName()
				{
					return Original.GetHostName();
				}

				public void VersionMatch()
				{
					if (finished)
					{
						Original.VersionMatch();
					}
					else
					{
						versionMatchQueued = Package.Count;
					}
				}

				public void Send(ZPackage pkg)
				{
					//IL_0057: Unknown result type (might be due to i