Decompiled source of Monocular v0.5.1

Monocular.dll

Decompiled 7 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JG224.ModCore.API;
using JG224.Monocular.Core;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("jg224")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("An equippable handheld monocular with mouse-wheel optical zoom for Valheim.")]
[assembly: AssemblyFileVersion("0.5.1.0")]
[assembly: AssemblyInformationalVersion("0.5.1")]
[assembly: AssemblyProduct("Monocular")]
[assembly: AssemblyTitle("Monocular")]
[assembly: AssemblyVersion("0.5.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace JG224.Monocular
{
	internal sealed class MonocularConfig
	{
		private readonly List<Tuple<ConfigEntryBase, ConfigScope>> _entries = new List<Tuple<ConfigEntryBase, ConfigScope>>();

		internal ConfigEntry<float> MaximumMagnification { get; }

		internal ConfigEntry<float> WheelStep { get; }

		internal ConfigEntry<float> TransitionSpeed { get; }

		internal ConfigEntry<float> FirstPersonTransitionSpeed { get; }

		internal ConfigEntry<bool> InvertMouseWheel { get; }

		internal bool DebugThirdPersonEnabled { get; }

		internal ConfigEntry<bool> ShowLensOverlay { get; }

		internal ConfigEntry<bool> ControllerZoom { get; }

		internal ConfigEntry<KeyboardShortcut> PresetHotkey { get; }

		internal ConfigEntry<float> NearPreset { get; }

		internal ConfigEntry<float> SurveyPreset { get; }

		internal ConfigEntry<float> DistancePreset { get; }

		internal MonocularConfig(ConfigFile file)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Expected O, but got Unknown
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Expected O, but got Unknown
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: 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_0173: Expected O, but got Unknown
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Expected O, but got Unknown
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<int> val = file.Bind<int>("Internal", "ConfigurationRevision", 1, new ConfigDescription("Internal settings migration revision.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 2), Array.Empty<object>()));
			MaximumMagnification = LocalRange(file, "Zoom", "MaximumMagnification", 20f, 2f, 20f, "Maximum optical magnification. 20 means twenty times magnification.");
			WheelStep = LocalRange(file, "Zoom", "MouseWheelStep", 1f, 0.05f, 2f, "Magnification added or removed for each mouse-wheel notch.");
			TransitionSpeed = LocalRange(file, "Zoom", "TransitionSpeed", 12f, 1f, 30f, "How quickly field of view eases toward the selected magnification.");
			FirstPersonTransitionSpeed = LocalRange(file, "Zoom", "FirstPersonTransitionSpeed", 6f, 0.5f, 15f, "How quickly equip eases the camera and field of view from third person to the eye.");
			InvertMouseWheel = Local(file, "Zoom", "InvertMouseWheel", value: false, "Reverse the mouse-wheel zoom direction.");
			DebugThirdPersonEnabled = file.Bind<bool>("Debug", "ThirdPersonEnabled", false, new ConfigDescription("CFG-only diagnostic: keep the normal third-person camera while equipped to inspect the held pose. Edit while stopped and restart to apply.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				Browsable = false
			} })).Value;
			file.Bind<KeyboardShortcut>("Debug", "ThirdPersonHotkey", KeyboardShortcut.Empty, new ConfigDescription("Deprecated and ignored. Existing bindings are retained only for configuration compatibility. Use ThirdPersonEnabled in this CFG and restart instead.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				Browsable = false
			} }));
			ShowLensOverlay = Local(file, "Display", "ShowLensOverlay", value: true, "Show the circular lens vignette and current magnification while the monocular is in use.");
			ControllerZoom = Local(file, "Zoom", "ControllerZoom", value: true, "D-pad up/down adjusts zoom while the monocular is usable; D-pad right cycles Near/Survey/Distance presets.");
			PresetHotkey = Local<KeyboardShortcut>(file, "Zoom", "CyclePresetHotkey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Cycle Near, Survey and Distance magnification presets.");
			NearPreset = LocalRange(file, "Zoom", "NearPreset", 2f, 1f, 20f, "Near preset magnification, capped by MaximumMagnification.");
			SurveyPreset = LocalRange(file, "Zoom", "SurveyPreset", 4f, 1f, 20f, "Survey preset magnification.");
			DistancePreset = LocalRange(file, "Zoom", "DistancePreset", 8f, 1f, 20f, "Distance preset magnification.");
			if (val.Value < 2)
			{
				MaximumMagnification.Value = 20f;
				val.Value = 2;
			}
		}

		internal IEnumerable<IDisposable> RegisterMetadata(ICoreServices services, ModuleId owner)
		{
			//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)
			foreach (Tuple<ConfigEntryBase, ConfigScope> entry2 in _entries)
			{
				ConfigEntryBase entry = entry2.Item1;
				yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, entry.Definition.Section, entry.Definition.Key, entry2.Item2, (Func<string>)(() => Convert.ToString(entry.BoxedValue, CultureInfo.InvariantCulture) ?? string.Empty), 1));
			}
		}

		private ConfigEntry<T> Local<T>(ConfigFile file, string section, string key, T value, string description)
		{
			return Add<T>(file.Bind<T>(section, key, value, description), (ConfigScope)1);
		}

		private ConfigEntry<float> LocalRange(ConfigFile file, string section, string key, float value, float minimum, float maximum, string description)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			return Add<float>(file.Bind<float>(section, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(minimum, maximum), Array.Empty<object>())), (ConfigScope)1);
		}

		private ConfigEntry<T> Add<T>(ConfigEntry<T> entry, ConfigScope scope)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			_entries.Add(Tuple.Create<ConfigEntryBase, ConfigScope>((ConfigEntryBase)(object)entry, scope));
			return entry;
		}
	}
	[BepInPlugin("jg224.Monocular", "Monocular", "0.5.1")]
	[BepInDependency("com.jg224.modcore", "0.5.0")]
	[BepInDependency("com.jotunn.jotunn", "2.30.0")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "jg224.Monocular";

		public const string PluginName = "Monocular";

		public const string PluginVersion = "0.5.1";

		public const string ModCoreGuid = "com.jg224.modcore";

		public const string ConfigFileName = "jg224.Monocular.cfg";

		public const int ProtocolVersion = 1;

		public static readonly ModuleId ModuleId = new ModuleId("monocular");

		private readonly List<IDisposable> _registrations = new List<IDisposable>();

		private Harmony? _harmony;

		private bool _itemReady;

		private bool _shutDown;

		internal static ManualLogSource Log { get; private set; } = null;

		internal static ICoreServices Core { get; private set; } = null;

		internal static MonocularConfig Settings { get; private set; } = null;

		private void Awake()
		{
			//IL_0237: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Expected O, but got Unknown
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				if (!ModCoreApi.IsAvailable)
				{
					throw new InvalidOperationException("ModCore did not initialize before Monocular.");
				}
				Core = ModCoreApi.Services;
				SemanticVersion val = default(SemanticVersion);
				if (!SemanticVersion.TryParse("0.5.1", ref val))
				{
					throw new InvalidOperationException("Monocular has invalid release version metadata.");
				}
				_registrations.Add(Core.Modules.Register(new ModuleDescriptor(ModuleId, "jg224.Monocular", "Monocular", val, 1, (ModuleSide)3, (ModuleRequirement)4, 0uL, 1, 1)));
				_registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)8, "monocular.", 1, Array.Empty<string>()));
				_registrations.Add(Core.Ui.Reserve(new UiReservation(ModuleId, (UiSurface)6, "center-screen.monocular-lens", 20, false)));
				_registrations.Add(Core.Input.Register(new InputActionDescriptor(ModuleId, "optical-zoom", "Mouse Wheel", "gameplay:monocular-equipped", 20)));
				_registrations.Add(Core.Input.Register(new InputActionDescriptor(ModuleId, "controller-optical-zoom", "D-pad Up/Down/Right", "gameplay:monocular-equipped-controller-enabled", 20)));
				PluginConfigFiles.Attach((BaseUnityPlugin)(object)this, ((BaseUnityPlugin)this).Config);
				if (!string.Equals(Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath), "jg224.Monocular.cfg", StringComparison.Ordinal))
				{
					throw new InvalidOperationException("Unexpected configuration filename: " + ((BaseUnityPlugin)this).Config.ConfigFilePath);
				}
				Settings = new MonocularConfig(((BaseUnityPlugin)this).Config);
				_registrations.AddRange(Settings.RegisterMetadata(Core, ModuleId));
				((BaseUnityPlugin)this).Config.Save();
				PrefabManager.OnVanillaPrefabsAvailable += RegisterItemWhenReady;
				_harmony = new Harmony("jg224.Monocular");
				_harmony.PatchAll(typeof(Plugin).Assembly);
				ValidateRuntimePatches();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Monocular 0.5.1 loaded; waiting for Jotunn's vanilla-prefab registration window.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogFatal((object)string.Format("{0} failed to initialize safely: {1}", "Monocular", ex));
				if (Core != null)
				{
					Core.Modules.SetState(ModuleId, (ModuleRuntimeState)5, ex.Message);
				}
				Shutdown();
				throw;
			}
		}

		private void OnGUI()
		{
			LensOverlay.Draw();
		}

		private void OnDestroy()
		{
			Shutdown();
		}

		private void ValidateRuntimePatches()
		{
			MethodBase[] source = _harmony.GetPatchedMethods().ToArray();
			bool flag = source.Any((MethodBase method) => method.DeclaringType == typeof(GameCamera) && method.Name == "UpdateCamera");
			bool flag2 = source.Any((MethodBase method) => method.DeclaringType == typeof(PlayerController) && method.Name == "LateUpdate");
			bool flag3 = source.Any((MethodBase method) => method.DeclaringType == typeof(ZInput) && method.Name == "GetButtonDown");
			bool flag4 = source.Any((MethodBase method) => method.DeclaringType == typeof(ZInput) && method.Name == "GetButton");
			if (!flag || !flag2 || !flag3 || !flag4)
			{
				throw new MissingMethodException("Monocular could not install its camera, mouse-look and controller input reservation patches.");
			}
		}

		private void RegisterItemWhenReady()
		{
			//IL_007c: 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)
			if (_shutDown || _itemReady)
			{
				return;
			}
			try
			{
				MonocularItem.Register();
				_itemReady = true;
				PrefabManager.OnVanillaPrefabsAvailable -= RegisterItemWhenReady;
				Core.Modules.SetState(ModuleId, (ModuleRuntimeState)2, "Required item prefab and client-local optical zoom are ready.");
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Monocular 0.5.1 registered jg224_monocular. Equip it to zoom.");
			}
			catch (Exception ex)
			{
				PrefabManager.OnVanillaPrefabsAvailable -= RegisterItemWhenReady;
				MonocularItem.Shutdown();
				Core.Modules.SetState(ModuleId, (ModuleRuntimeState)5, ex.Message);
				((BaseUnityPlugin)this).Logger.LogError((object)string.Format("{0} could not register its item when vanilla prefabs became available: {1}", "Monocular", ex));
			}
		}

		private void Shutdown()
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			if (_shutDown)
			{
				return;
			}
			_shutDown = true;
			PrefabManager.OnVanillaPrefabsAvailable -= RegisterItemWhenReady;
			ZoomRuntime.RestoreAndReset();
			LensOverlay.Shutdown();
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			_harmony = null;
			MonocularItem.Shutdown();
			for (int num = _registrations.Count - 1; num >= 0; num--)
			{
				try
				{
					_registrations[num].Dispose();
				}
				catch (Exception ex)
				{
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogWarning((object)("Could not release a ModCore registration: " + ex.Message));
					}
				}
			}
			_registrations.Clear();
			if (Core != null)
			{
				Core.Metrics.RemoveOwner(ModuleId);
			}
		}
	}
	[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
	[HarmonyAfter(new string[] { "com.jg224.bettercombat" })]
	internal static class CameraZoomPatch
	{
		private static readonly MethodInfo WheelMethod = AccessTools.Method(typeof(ZInput), "GetMouseScrollWheel", (Type[])null, (Type[])null);

		private static readonly MethodInfo CameraWheelMethod = AccessTools.Method(typeof(CameraZoomPatch), "GetMouseScrollWheelForCamera", (Type[])null, (Type[])null);

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			int num = 0;
			foreach (CodeInstruction item in list)
			{
				if (CodeInstructionExtensions.Calls(item, WheelMethod))
				{
					item.opcode = OpCodes.Call;
					item.operand = CameraWheelMethod;
					num++;
				}
			}
			if (num == 0)
			{
				throw new MissingMethodException("GameCamera.UpdateCamera no longer calls ZInput.GetMouseScrollWheel; refusing an unsafe zoom patch.");
			}
			return list;
		}

		private static float GetMouseScrollWheelForCamera()
		{
			if (!ZoomRuntime.ShouldConsumeCameraWheel())
			{
				return ZInput.GetMouseScrollWheel();
			}
			return 0f;
		}

		private static void Postfix(GameCamera __instance, float dt)
		{
			ZoomRuntime.UpdateCamera(__instance, dt);
		}
	}
	[HarmonyPatch(typeof(ZInput), "GetButtonDown", new Type[] { typeof(string) })]
	internal static class ControllerButtonDownPatch
	{
		private static bool Prefix(string __0, ref bool __result)
		{
			if (!ZoomRuntime.ShouldReserveControllerAlias(__0))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(ZInput), "GetButton", new Type[] { typeof(string) })]
	internal static class ControllerButtonHeldPatch
	{
		private static bool Prefix(string __0, ref bool __result)
		{
			if (!ZoomRuntime.ShouldReserveControllerAlias(__0))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	internal static class LensOverlay
	{
		private static Texture2D? _mask;

		private static GUIStyle? _labelStyle;

		internal static void Draw()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: 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_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Event.current.type == 7 && ZoomRuntime.OverlayVisible)
			{
				EnsureResources();
				int num = Math.Max(1, (int)Math.Floor((float)Math.Min(Screen.width, Screen.height) * 0.94f));
				int num2 = (Screen.width - num) / 2;
				int num3 = (Screen.height - num) / 2;
				int num4 = num2 + num;
				int num5 = num3 + num;
				Rect val = new Rect((float)num2, (float)num3, (float)num, (float)num);
				float num6 = Mathf.Clamp01(ZoomRuntime.ViewBlend);
				Color color = GUI.color;
				GUI.color = new Color(0f, 0f, 0f, 0.96f * num6);
				if ((float)num2 > 0f)
				{
					GUI.DrawTexture(new Rect(0f, 0f, (float)(num2 + 2), (float)Screen.height), (Texture)(object)Texture2D.whiteTexture);
					GUI.DrawTexture(new Rect((float)(num4 - 2), 0f, (float)(Screen.width - num4 + 2), (float)Screen.height), (Texture)(object)Texture2D.whiteTexture);
				}
				if ((float)num3 > 0f)
				{
					GUI.DrawTexture(new Rect((float)(num2 - 2), 0f, (float)(num + 4), (float)(num3 + 2)), (Texture)(object)Texture2D.whiteTexture);
					GUI.DrawTexture(new Rect((float)(num2 - 2), (float)(num5 - 2), (float)(num + 4), (float)(Screen.height - num5 + 2)), (Texture)(object)Texture2D.whiteTexture);
				}
				GUI.color = new Color(1f, 1f, 1f, num6);
				GUI.DrawTexture(val, (Texture)(object)_mask, (ScaleMode)0, true);
				GUI.Label(new Rect((float)num2, (float)(num3 + num) - 52f, (float)num, 36f), string.Format("{0:0.00}×  •  {1}", ZoomRuntime.Magnification, (ZInput.IsGamepadActive() && Plugin.Settings.ControllerZoom.Value) ? "D-pad ↑↓ Zoom / → Preset" : ("Wheel Zoom / " + ((object)Plugin.Settings.PresetHotkey.Value/*cast due to .constrained prefix*/).ToString() + " Preset")), _labelStyle);
				GUI.color = color;
			}
		}

		internal static void Shutdown()
		{
			if ((Object)(object)_mask != (Object)null)
			{
				Object.Destroy((Object)(object)_mask);
				_mask = null;
			}
			_labelStyle = null;
		}

		private static void EnsureResources()
		{
			//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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_mask == (Object)null)
			{
				_mask = new Texture2D(256, 256, (TextureFormat)4, false)
				{
					name = "MonocularLensVignette",
					hideFlags = (HideFlags)61,
					wrapMode = (TextureWrapMode)1,
					filterMode = (FilterMode)1
				};
				Color32[] array = (Color32[])(object)new Color32[65536];
				for (int i = 0; i < 256; i++)
				{
					for (int j = 0; j < 256; j++)
					{
						float num = ((float)j + 0.5f) / 256f * 2f - 1f;
						float num2 = ((float)i + 0.5f) / 256f * 2f - 1f;
						float num3 = Mathf.Sqrt(num * num + num2 * num2);
						float num4 = Mathf.SmoothStep(0f, 0.96f, Mathf.InverseLerp(0.82f, 0.96f, num3));
						array[i * 256 + j] = Color32.op_Implicit(new Color(0f, 0f, 0f, num4));
					}
				}
				_mask.SetPixels32(array);
				_mask.Apply(false, true);
			}
			if (_labelStyle == null)
			{
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					fontSize = 18,
					fontStyle = (FontStyle)1
				};
				val.normal.textColor = new Color(0.82f, 0.95f, 0.96f, 0.95f);
				_labelStyle = val;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerController), "LateUpdate")]
	internal static class LookSensitivityPatch
	{
		private static readonly MethodInfo MouseDeltaMethod = AccessTools.Method(typeof(ZInput), "GetMouseDelta", Type.EmptyTypes, (Type[])null);

		private static readonly MethodInfo ScaledMouseDeltaMethod = AccessTools.Method(typeof(LookSensitivityPatch), "GetScaledMouseDelta", (Type[])null, (Type[])null);

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			int num = 0;
			foreach (CodeInstruction item in list)
			{
				if (CodeInstructionExtensions.Calls(item, MouseDeltaMethod))
				{
					item.opcode = OpCodes.Call;
					item.operand = ScaledMouseDeltaMethod;
					num++;
				}
			}
			if (num != 1)
			{
				throw new MissingMethodException("PlayerController.LateUpdate no longer contains exactly one ZInput.GetMouseDelta call; refusing an unsafe sensitivity patch.");
			}
			return list;
		}

		private static Vector2 GetScaledMouseDelta()
		{
			//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)
			return ZoomRuntime.ScaleMouseDelta(ZInput.GetMouseDelta());
		}
	}
	[DefaultExecutionOrder(1000)]
	internal sealed class MonocularHeldPose : MonoBehaviour
	{
		private const float AttachmentForwardOffset = 0.162f;

		private const float RightEyeOffset = 0.032f;

		private const float HandForwardOffset = 0.12f;

		private const float HandRightOffset = 0.075f;

		private const float HandDownOffset = 0.035f;

		private static readonly FieldRef<Character, Animator> CharacterAnimator = AccessTools.FieldRefAccess<Character, Animator>("m_animator");

		private Character? _owner;

		private Transform? _upperArm;

		private Transform? _lowerArm;

		private Transform? _rightHand;

		private Renderer[]? _renderers;

		private bool? _renderersVisible;

		private void LateUpdate()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_008b: 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_0090: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_owner == (Object)null)
			{
				_owner = ((Component)this).GetComponentInParent<Character>();
			}
			if (!((Object)(object)_owner == (Object)null))
			{
				Vector3 val = _owner.GetLookDir();
				if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
				{
					val = ((Component)_owner).transform.forward;
				}
				((Vector3)(ref val)).Normalize();
				Vector3 val2 = (((Object)(object)_owner.m_eye != (Object)null) ? _owner.m_eye.up : ((Component)_owner).transform.up);
				Vector3 val4;
				if (!((Object)(object)_owner.m_eye != (Object)null))
				{
					Vector3 val3 = Vector3.Cross(val2, val);
					val4 = ((Vector3)(ref val3)).normalized;
				}
				else
				{
					val4 = _owner.m_eye.right;
				}
				Vector3 val5 = val4;
				ApplyRightArmPose(val, val2, val5);
				((Component)this).transform.position = _owner.GetEyePoint() + val * 0.162f + val5 * 0.032f;
				((Component)this).transform.rotation = Quaternion.LookRotation(val, val2);
				SetRenderersVisible((Object)(object)_owner != (Object)(object)Player.m_localPlayer || !ZoomRuntime.HideLocalHeldModel);
			}
		}

		private void ApplyRightArmPose(Vector3 forward, Vector3 up, Vector3 right)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: 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_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: 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_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: 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_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: 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_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: 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_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: 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_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: 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_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			if (!ResolveRightArm() || (Object)(object)_owner == (Object)null || (Object)(object)_upperArm == (Object)null || (Object)(object)_lowerArm == (Object)null || (Object)(object)_rightHand == (Object)null)
			{
				return;
			}
			Vector3 position = _upperArm.position;
			Vector3 position2 = _lowerArm.position;
			Vector3 position3 = _rightHand.position;
			float upperLength = Vector3.Distance(position, position2);
			float lowerLength = Vector3.Distance(position2, position3);
			Vector3 val = _owner.GetEyePoint() + forward * 0.12f + right * 0.075f - up * 0.035f - position;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (TwoBoneMath.TrySolve(upperLength, lowerLength, magnitude, out var along, out var bend, out var solvedDistance))
			{
				Vector3 val2 = val / magnitude;
				Vector3 val3 = right * 0.75f - up * 0.4f + forward * 0.15f;
				Vector3 val4 = val3 - val2 * Vector3.Dot(val3, val2);
				if (((Vector3)(ref val4)).sqrMagnitude < 0.001f)
				{
					val4 = Vector3.Cross(val2, up);
				}
				if (((Vector3)(ref val4)).sqrMagnitude < 0.001f)
				{
					val4 = right;
				}
				((Vector3)(ref val4)).Normalize();
				Vector3 val5 = position + val2 * along + val4 * bend;
				Vector3 val6 = _lowerArm.position - position;
				Vector3 val7 = val5 - position;
				if (((Vector3)(ref val6)).sqrMagnitude > 0.001f && ((Vector3)(ref val7)).sqrMagnitude > 0.001f)
				{
					_upperArm.rotation = Quaternion.FromToRotation(val6, val7) * _upperArm.rotation;
				}
				position2 = _lowerArm.position;
				Vector3 val8 = position + val2 * solvedDistance;
				Vector3 val9 = _rightHand.position - position2;
				Vector3 val10 = val8 - position2;
				if (((Vector3)(ref val9)).sqrMagnitude > 0.001f && ((Vector3)(ref val10)).sqrMagnitude > 0.001f)
				{
					_lowerArm.rotation = Quaternion.FromToRotation(val9, val10) * _lowerArm.rotation;
				}
			}
		}

		private bool ResolveRightArm()
		{
			if ((Object)(object)_upperArm != (Object)null && (Object)(object)_lowerArm != (Object)null && (Object)(object)_rightHand != (Object)null)
			{
				return true;
			}
			if ((Object)(object)_owner == (Object)null)
			{
				return false;
			}
			Animator val = CharacterAnimator.Invoke(_owner);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			_upperArm = Utils.GetBoneTransform(val, (HumanBodyBones)14);
			_lowerArm = Utils.GetBoneTransform(val, (HumanBodyBones)16);
			_rightHand = Utils.GetBoneTransform(val, (HumanBodyBones)18);
			if ((Object)(object)_upperArm != (Object)null && (Object)(object)_lowerArm != (Object)null)
			{
				return (Object)(object)_rightHand != (Object)null;
			}
			return false;
		}

		private void SetRenderersVisible(bool visible)
		{
			if (_renderersVisible != visible)
			{
				if (_renderers == null)
				{
					_renderers = ((Component)this).GetComponentsInChildren<Renderer>(true);
				}
				Renderer[] renderers = _renderers;
				for (int i = 0; i < renderers.Length; i++)
				{
					renderers[i].enabled = visible;
				}
				_renderersVisible = visible;
			}
		}
	}
	internal static class MonocularItem
	{
		internal const string PrefabName = "jg224_monocular";

		private const string IconFileName = "monocular-inventory.png";

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

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

		private static CustomItem? _customItem;

		private static KeyHintConfig? _keyHint;

		private static bool _itemAdded;

		private static bool _keyHintAdded;

		private static readonly List<Object> OwnedObjects = new List<Object>();

		internal static void Register()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			//IL_00e2: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: 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)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Expected O, but got Unknown
			RegisterLocalization();
			Sprite icon = LoadIcon();
			ItemConfig val = new ItemConfig();
			val.Name = "$item_monocular";
			val.Description = "$item_monocular_description";
			val.CraftingStation = "piece_workbench";
			val.MinStationLevel = 1;
			val.Amount = 1;
			val.Weight = 1f;
			val.StackSize = 1;
			val.Icon = icon;
			val.Requirements = (RequirementConfig[])(object)new RequirementConfig[1]
			{
				new RequirementConfig("FineWood", 2, 0, true)
			};
			ItemConfig val2 = val;
			_customItem = new CustomItem("jg224_monocular", "Hammer", val2);
			ConfigureSharedData(_customItem, icon);
			ReplaceToolVisuals(_customItem.ItemPrefab);
			if (!ItemManager.Instance.AddItem(_customItem))
			{
				throw new InvalidOperationException("Jotunn rejected the Monocular item registration.");
			}
			_itemAdded = true;
			KeyHintConfig val3 = new KeyHintConfig();
			val3.Item = "jg224_monocular";
			val3.ButtonConfigs = (ButtonConfig[])(object)new ButtonConfig[1]
			{
				new ButtonConfig
				{
					Name = "monocular-optical-zoom",
					Axis = "Mouse ScrollWheel",
					Hint = "Zoom",
					ActiveInGUI = false,
					BlockOtherInputs = false
				}
			};
			_keyHint = val3;
			if (!KeyHintManager.Instance.AddKeyHint(_keyHint))
			{
				throw new InvalidOperationException("Jotunn rejected the Monocular key-hint registration.");
			}
			_keyHintAdded = true;
		}

		internal static bool IsEquipped(Player? player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (!IsMonocular(RightItem.Invoke((Humanoid)(object)player)))
			{
				return IsMonocular(LeftItem.Invoke((Humanoid)(object)player));
			}
			return true;
		}

		internal static void Shutdown()
		{
			if (_keyHintAdded && _keyHint != null)
			{
				KeyHintManager.Instance.RemoveKeyHint(_keyHint);
			}
			_keyHintAdded = false;
			_keyHint = null;
			if (_itemAdded && _customItem != null && Object.op_Implicit((Object)(object)_customItem.ItemPrefab))
			{
				ItemManager.Instance.RemoveItem(_customItem);
			}
			_itemAdded = false;
			_customItem = null;
			foreach (Object ownedObject in OwnedObjects)
			{
				if (Object.op_Implicit(ownedObject))
				{
					Object.Destroy(ownedObject);
				}
			}
			OwnedObjects.Clear();
		}

		private static bool IsMonocular(ItemData? item)
		{
			if ((Object)(object)item?.m_dropPrefab != (Object)null)
			{
				return string.Equals(((Object)item.m_dropPrefab).name, "jg224_monocular", StringComparison.Ordinal);
			}
			return false;
		}

		private static void ConfigureSharedData(CustomItem item, Sprite icon)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			SharedData obj = item.ItemDrop?.m_itemData?.m_shared ?? throw new InvalidOperationException("The cloned Hammer prefab has no ItemDrop shared data.");
			obj.m_name = "$item_monocular";
			obj.m_description = "$item_monocular_description";
			obj.m_itemType = (ItemType)19;
			obj.m_animationState = (AnimationState)5;
			obj.m_maxStackSize = 1;
			obj.m_maxQuality = 1;
			obj.m_weight = 1f;
			obj.m_useDurability = false;
			obj.m_canBeReparied = false;
			obj.m_teleportable = true;
			obj.m_questItem = false;
			obj.m_buildPieces = null;
			obj.m_icons = (Sprite[])(object)new Sprite[1] { icon };
		}

		private static void RegisterLocalization()
		{
			string text = "English";
			Dictionary<string, string> dictionary = new Dictionary<string, string>
			{
				["item_monocular"] = "Monocular",
				["item_monocular_description"] = "A compact brass-and-oak spyglass. Equip it to ease into a 2x eye view and use the mouse wheel to zoom."
			};
			LocalizationManager.Instance.GetLocalization().AddTranslation(ref text, dictionary);
		}

		private static Sprite LoadIcon()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, "monocular-inventory.png");
			Texture2D val = AssetUtils.LoadTexture(text, false);
			if ((Object)(object)val == (Object)null)
			{
				throw new FileNotFoundException("Monocular inventory icon is missing beside the plugin DLL. Reinstall the complete package.", text);
			}
			((Object)val).name = "MonocularIcon";
			((Object)val).hideFlags = (HideFlags)61;
			OwnedObjects.Add((Object)(object)val);
			Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			((Object)val2).name = "MonocularIcon";
			((Object)val2).hideFlags = (HideFlags)61;
			OwnedObjects.Add((Object)(object)val2);
			return val2;
		}

		private static void ReplaceToolVisuals(GameObject prefab)
		{
			//IL_0044: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			Transform? obj = FindDirectChild(prefab.transform, "attach");
			if ((Object)(object)obj == (Object)null)
			{
				throw new InvalidOperationException("The cloned Hammer prefab has no attach transform.");
			}
			Material template = FindTemplateMaterial(obj);
			Material brass = CreateMaterial(template, "MonocularBrass", new Color(0.68f, 0.44f, 0.14f, 1f), 0.12f);
			Material wood = CreateMaterial(template, "MonocularWood", new Color(0.27f, 0.11f, 0.045f, 1f), 0.035f);
			Material val = CreateMaterial(template, "MonocularLens", new Color(0.03f, 0.58f, 0.7f, 1f), 0.35f);
			if (val.HasProperty("_Metallic"))
			{
				val.SetFloat("_Metallic", 0.65f);
			}
			if (val.HasProperty("_Glossiness"))
			{
				val.SetFloat("_Glossiness", 0.9f);
			}
			RebuildAttachment(obj, brass, wood, val, backAttach: false);
			Transform val2 = FindDirectChild(prefab.transform, "attach_back");
			if ((Object)(object)val2 != (Object)null)
			{
				RebuildAttachment(val2, brass, wood, val, backAttach: true);
			}
		}

		private static void RebuildAttachment(Transform attach, Material brass, Material wood, Material lens, bool backAttach)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: 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_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: 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_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = ((Component)attach).GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			MeshFilter[] componentsInChildren2 = ((Component)attach).GetComponentsInChildren<MeshFilter>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
			}
			GameObject val = new GameObject("MonocularModel");
			val.transform.SetParent(attach, false);
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.Euler(90f, 0f, backAttach ? 90f : 0f);
			if (!backAttach && (Object)(object)((Component)attach).GetComponent<MonocularHeldPose>() == (Object)null)
			{
				((Component)attach).gameObject.AddComponent<MonocularHeldPose>();
			}
			CreateCylinder(val.transform, "OakTube", new Vector3(0f, 0f, 0f), 0.052f, 0.29f, wood);
			CreateCylinder(val.transform, "FrontBell", new Vector3(0f, 0.16f, 0f), 0.072f, 0.065f, brass);
			CreateCylinder(val.transform, "FrontRing", new Vector3(0f, 0.115f, 0f), 0.061f, 0.025f, brass);
			CreateCylinder(val.transform, "CenterRing", new Vector3(0f, 0f, 0f), 0.06f, 0.025f, brass);
			CreateCylinder(val.transform, "EyeRing", new Vector3(0f, -0.15f, 0f), 0.063f, 0.05f, brass);
			CreateCylinder(val.transform, "Glass", new Vector3(0f, 0.195f, 0f), 0.061f, 0.012f, lens);
		}

		private static void CreateCylinder(Transform parent, string name, Vector3 position, float radius, float length, Material material)
		{
			//IL_0020: 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)
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)2);
			((Object)obj).name = name;
			obj.transform.SetParent(parent, false);
			obj.transform.localPosition = position;
			obj.transform.localScale = new Vector3(radius, length * 0.5f, radius);
			Collider component = obj.GetComponent<Collider>();
			if ((Object)(object)component != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component);
			}
			((Renderer)obj.GetComponent<MeshRenderer>()).sharedMaterial = material;
		}

		private static Material FindTemplateMaterial(Transform attach)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			Renderer[] componentsInChildren = ((Component)attach).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if ((Object)(object)val.sharedMaterial != (Object)null)
				{
					return val.sharedMaterial;
				}
			}
			Shader obj = Shader.Find("Standard");
			if ((Object)(object)obj == (Object)null)
			{
				throw new InvalidOperationException("No material was available for the Monocular model.");
			}
			Material val2 = new Material(obj);
			OwnedObjects.Add((Object)(object)val2);
			return val2;
		}

		private static Material CreateMaterial(Material template, string name, Color color, float emissionStrength)
		{
			//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_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0030: 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_005c: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			Material val = new Material(template)
			{
				name = name,
				color = color,
				hideFlags = (HideFlags)61
			};
			if (val.HasProperty("_Color"))
			{
				val.SetColor("_Color", color);
			}
			if (val.HasProperty("_EmissionColor"))
			{
				val.EnableKeyword("_EMISSION");
				val.SetColor("_EmissionColor", new Color(color.r * emissionStrength, color.g * emissionStrength, color.b * emissionStrength, 1f));
			}
			OwnedObjects.Add((Object)(object)val);
			return val;
		}

		private static Transform? FindDirectChild(Transform parent, string name)
		{
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				if (string.Equals(((Object)child).name, name, StringComparison.Ordinal))
				{
					return child;
				}
			}
			return null;
		}
	}
	internal static class ZoomRuntime
	{
		private const float EyeCameraForwardOffset = 0.08f;

		private static readonly FieldRef<GameCamera, Camera> MainCamera = AccessTools.FieldRefAccess<GameCamera, Camera>("m_camera");

		private static bool _equipped;

		private static bool _cameraOverrideApplied;

		private static bool _overlayVisible;

		private static float _magnification = 2f;

		private static float _currentFov = -1f;

		private static float _viewBlend;

		private static GameCamera? _cameraOwner;

		private static float _originalNearClip;

		private static float _appliedNearClip;

		private static Vector3 _nativePosition;

		private static Vector3 _appliedPosition;

		private static Quaternion _nativeRotation;

		private static Quaternion _appliedRotation;

		private static int _presetIndex;

		internal static float Magnification => _magnification;

		internal static bool OverlayVisible => _overlayVisible;

		internal static float ViewBlend => _viewBlend;

		internal static bool DebugThirdPersonEnabled => Plugin.Settings?.DebugThirdPersonEnabled ?? false;

		internal static bool HideLocalHeldModel
		{
			get
			{
				if (!DebugThirdPersonEnabled)
				{
					return _viewBlend >= 0.85f;
				}
				return false;
			}
		}

		internal static bool ShouldConsumeCameraWheel()
		{
			if (!DebugThirdPersonEnabled && TryGetUsablePlayer(out Player _))
			{
				return CanAcceptGameplayInput();
			}
			return false;
		}

		internal static bool ShouldReserveControllerAlias(string name)
		{
			if (ControllerInputRules.IsNativeAlias(name))
			{
				MonocularConfig settings = Plugin.Settings;
				if (settings != null && settings.ControllerZoom.Value && ZInput.IsGamepadActive() && !DebugThirdPersonEnabled && TryGetUsablePlayer(out Player _) && CanAcceptGameplayInput())
				{
					return ControllerInputRules.Conflicts(name, ZInput.GetButton("JoyDPadUp"), ZInput.GetButton("JoyDPadDown"), ZInput.GetButton("JoyDPadRight"));
				}
			}
			return false;
		}

		internal static Vector2 ScaleMouseDelta(Vector2 delta)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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)
			GameCamera instance = GameCamera.instance;
			if (!_cameraOverrideApplied || DebugThirdPersonEnabled || (Object)(object)instance == (Object)null || !TryGetUsablePlayer(out Player _))
			{
				return delta;
			}
			return delta * ZoomMath.LookSensitivityForFov(instance.m_fov, _currentFov);
		}

		internal static void UpdateCamera(GameCamera camera, float deltaTime)
		{
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_cameraOwner != (Object)(object)camera)
			{
				if ((Object)(object)_cameraOwner != (Object)null)
				{
					RestoreCamera(_cameraOwner);
				}
				ResetState();
				_cameraOwner = camera;
			}
			if (!TryGetUsablePlayer(out Player player) || DebugThirdPersonEnabled)
			{
				RestoreCamera(camera);
				ResetState();
				return;
			}
			float fov = camera.m_fov;
			if (!_equipped)
			{
				_equipped = true;
				_magnification = ZoomMath.ClampMagnification(2f, Plugin.Settings.MaximumMagnification.Value);
				_currentFov = fov;
				_viewBlend = 0f;
			}
			bool flag = CanAcceptGameplayInput();
			if (!flag)
			{
				RestoreCamera(camera);
				_cameraOverrideApplied = false;
				_overlayVisible = false;
				_viewBlend = 0f;
				_currentFov = fov;
				return;
			}
			int num;
			int num2;
			if (flag)
			{
				float mouseScrollWheel = ZInput.GetMouseScrollWheel();
				_magnification = ZoomMath.ApplyWheel(_magnification, mouseScrollWheel, Plugin.Settings.WheelStep.Value, Plugin.Settings.MaximumMagnification.Value, Plugin.Settings.InvertMouseWheel.Value);
				if (Plugin.Settings.ControllerZoom.Value)
				{
					num = (ZInput.IsGamepadActive() ? 1 : 0);
					if (num != 0)
					{
						num2 = (ZInput.GetButtonDown("JoyDPadUp") ? 1 : 0);
						goto IL_012d;
					}
				}
				else
				{
					num = 0;
				}
				num2 = 0;
				goto IL_012d;
			}
			goto IL_0230;
			IL_0230:
			_viewBlend = ZoomMath.AdvanceTransition(_viewBlend, Plugin.Settings.FirstPersonTransitionSpeed.Value, deltaTime);
			float target = ZoomMath.FovForMagnification(fov, _magnification);
			float response = ((_viewBlend < 0.995f) ? Plugin.Settings.FirstPersonTransitionSpeed.Value : Plugin.Settings.TransitionSpeed.Value);
			_currentFov = ZoomMath.SmoothFov((_currentFov < 0f) ? fov : _currentFov, target, response, deltaTime);
			ApplyEyeView(camera, player, _viewBlend);
			SetCameraFov(camera, _currentFov);
			_cameraOverrideApplied = true;
			_overlayVisible = flag && Plugin.Settings.ShowLensOverlay.Value;
			return;
			IL_012d:
			bool flag2 = (byte)num2 != 0;
			bool flag3 = num != 0 && ZInput.GetButtonDown("JoyDPadDown");
			if (flag2 || flag3)
			{
				_magnification = ZoomMath.ApplyWheel(_magnification, flag2 ? 1f : (-1f), Plugin.Settings.WheelStep.Value, Plugin.Settings.MaximumMagnification.Value, inverted: false);
				ZInput.ResetButtonStatus(flag2 ? "JoyDPadUp" : "JoyDPadDown");
			}
			bool flag4 = num != 0 && ZInput.GetButtonDown("JoyDPadRight");
			KeyboardShortcut value = Plugin.Settings.PresetHotkey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown() || flag4)
			{
				_presetIndex = (_presetIndex + 1) % 3;
				_magnification = ZoomMath.Preset(_presetIndex, Plugin.Settings.NearPreset.Value, Plugin.Settings.SurveyPreset.Value, Plugin.Settings.DistancePreset.Value, Plugin.Settings.MaximumMagnification.Value);
				if (flag4)
				{
					ZInput.ResetButtonStatus("JoyDPadRight");
				}
			}
			goto IL_0230;
		}

		internal static void RestoreAndReset()
		{
			if ((Object)(object)GameCamera.instance != (Object)null)
			{
				RestoreCamera(GameCamera.instance);
			}
			ResetState();
		}

		private static bool TryGetUsablePlayer(out Player? player)
		{
			player = Player.m_localPlayer;
			if ((Object)(object)player != (Object)null)
			{
				return ZoomMath.CanUse(!((Character)player).IsDead() && ((Character)player).GetHealth() > 0f, ((Character)player).IsTeleporting(), ((Character)player).InCutscene(), ((Character)player).IsAttached(), MonocularItem.IsEquipped(player));
			}
			return false;
		}

		private static bool CanAcceptGameplayInput()
		{
			if (((Object)(object)Chat.instance == (Object)null || !Chat.instance.HasFocus()) && !InventoryGui.IsVisible() && !Menu.IsVisible() && !StoreGui.IsVisible() && !Console.IsVisible() && !TextInput.IsVisible() && !Minimap.IsOpen() && !Hud.IsPieceSelectionVisible())
			{
				return !Hud.InRadial();
			}
			return false;
		}

		private static void RestoreCamera(GameCamera camera)
		{
			//IL_0076: 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)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			if (_cameraOverrideApplied)
			{
				Camera val = MainCamera.Invoke(camera);
				if ((Object)(object)val != (Object)null && Mathf.Abs(val.fieldOfView - _currentFov) < 0.1f)
				{
					SetCameraFov(camera, camera.m_fov);
				}
				if ((Object)(object)val != (Object)null && Mathf.Abs(val.nearClipPlane - _appliedNearClip) < 0.001f)
				{
					val.nearClipPlane = _originalNearClip;
				}
				Vector3 val2 = ((Component)camera).transform.position - _appliedPosition;
				if (((Vector3)(ref val2)).sqrMagnitude < 1E-06f)
				{
					((Component)camera).transform.position = _nativePosition;
				}
				if (Quaternion.Angle(((Component)camera).transform.rotation, _appliedRotation) < 0.01f)
				{
					((Component)camera).transform.rotation = _nativeRotation;
				}
			}
		}

		private static void SetCameraFov(GameCamera camera, float fov)
		{
			Camera val = MainCamera.Invoke(camera);
			if ((Object)(object)val != (Object)null)
			{
				val.fieldOfView = fov;
			}
			if ((Object)(object)camera.m_skyCamera != (Object)null)
			{
				camera.m_skyCamera.fieldOfView = fov;
			}
		}

		private static void ApplyEyeView(GameCamera camera, Player player, float blend)
		{
			//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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_0026: 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_0069: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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_00bc: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: 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)
			_nativePosition = ((Component)camera).transform.position;
			_nativeRotation = ((Component)camera).transform.rotation;
			Vector3 val = ((Character)player).GetLookDir();
			if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
			{
				val = ((Component)player).transform.forward;
			}
			((Vector3)(ref val)).Normalize();
			Vector3 val2 = (((Object)(object)((Character)player).m_eye != (Object)null) ? ((Character)player).m_eye.up : ((Component)player).transform.up);
			Vector3 val3 = ((Character)player).GetEyePoint() + val * 0.08f;
			Quaternion val4 = Quaternion.LookRotation(val, val2);
			((Component)camera).transform.position = Vector3.Lerp(((Component)camera).transform.position, val3, blend);
			((Component)camera).transform.rotation = Quaternion.Slerp(((Component)camera).transform.rotation, val4, blend);
			_appliedPosition = ((Component)camera).transform.position;
			_appliedRotation = ((Component)camera).transform.rotation;
			Camera val5 = MainCamera.Invoke(camera);
			if ((Object)(object)val5 != (Object)null)
			{
				if (!_cameraOverrideApplied || Mathf.Abs(val5.nearClipPlane - _appliedNearClip) > 0.001f)
				{
					_originalNearClip = val5.nearClipPlane;
				}
				val5.nearClipPlane = Mathf.Lerp(val5.nearClipPlane, camera.m_nearClipPlaneMin, blend);
				_appliedNearClip = val5.nearClipPlane;
			}
		}

		private static void ResetState()
		{
			_equipped = false;
			_cameraOverrideApplied = false;
			_overlayVisible = false;
			_magnification = 2f;
			_currentFov = -1f;
			_viewBlend = 0f;
			_cameraOwner = null;
			_presetIndex = 0;
		}
	}
}
namespace JG224.Monocular.Core
{
	internal static class ControllerInputRules
	{
		internal static bool IsNativeAlias(string name)
		{
			switch (name)
			{
			default:
				return name == "JoyMiniMapZoomIn";
			case "JoyHotbarUse":
			case "JoyHotbarRight":
			case "JoyCamZoomIn":
			case "JoyCamZoomOut":
			case "JoySit":
			case "JoyGP":
				return true;
			}
		}

		internal static bool Conflicts(string name, bool up, bool down, bool right)
		{
			switch (name)
			{
			case "JoyCamZoomIn":
			case "JoyHotbarUse":
				return up;
			case "JoyCamZoomOut":
			case "JoySit":
			case "JoyGP":
				return down;
			case "JoyHotbarRight":
			case "JoyMiniMapZoomIn":
				return right;
			default:
				return false;
			}
		}
	}
	internal static class TwoBoneMath
	{
		internal static bool TrySolve(float upperLength, float lowerLength, float targetDistance, out float along, out float bend, out float solvedDistance)
		{
			along = 0f;
			bend = 0f;
			solvedDistance = 0f;
			if (upperLength <= 0.001f || lowerLength <= 0.001f || targetDistance <= 0.001f)
			{
				return false;
			}
			float num = Math.Abs(upperLength - lowerLength) + 0.001f;
			float num2 = upperLength + lowerLength - 0.001f;
			if (num2 <= num)
			{
				return false;
			}
			solvedDistance = Math.Max(num, Math.Min(num2, targetDistance));
			along = (upperLength * upperLength + solvedDistance * solvedDistance - lowerLength * lowerLength) / (2f * solvedDistance);
			bend = (float)Math.Sqrt(Math.Max(0f, upperLength * upperLength - along * along));
			return true;
		}
	}
	internal static class ZoomMath
	{
		internal const float MinimumMagnification = 1f;

		internal const float EquippedMagnification = 2f;

		internal static float Preset(int index, float near, float survey, float distance, float maximum)
		{
			return ClampMagnification((index % 3 == 0) ? near : ((index % 3 == 1) ? survey : distance), maximum);
		}

		internal static bool CanUse(bool alive, bool teleporting, bool cutscene, bool attached, bool equipped)
		{
			return alive && !teleporting && !cutscene && !attached && equipped;
		}

		internal static float ApplyWheel(float current, float wheelDelta, float step, float maximum, bool inverted)
		{
			float num = ClampMagnification(current, maximum);
			if (Math.Abs(wheelDelta) < 0.0001f)
			{
				return num;
			}
			float num2 = ((wheelDelta > 0f) ? 1f : (-1f));
			if (inverted)
			{
				num2 = 0f - num2;
			}
			return ClampMagnification(num + num2 * Math.Max(0.01f, step), maximum);
		}

		internal static float FovForMagnification(float normalFov, float magnification)
		{
			double num = Math.Max(1.0, Math.Min(179.0, normalFov));
			double num2 = Math.Max(1f, magnification);
			double a = num * Math.PI / 360.0;
			return (float)(2.0 * Math.Atan(Math.Tan(a) / num2) * 180.0 / Math.PI);
		}

		internal static float LookSensitivityForFov(float normalFov, float displayedFov)
		{
			double a = Math.Max(1.0, Math.Min(179.0, normalFov)) * Math.PI / 360.0;
			double val = Math.Tan(Math.Max(1.0, Math.Min(179.0, displayedFov)) * Math.PI / 360.0) / Math.Tan(a);
			return (float)Math.Max(0.01, Math.Min(1.0, val));
		}

		internal static float SmoothFov(float current, float target, float response, float deltaTime)
		{
			if (deltaTime <= 0f)
			{
				return current;
			}
			double num = 1.0 - Math.Exp((0f - Math.Max(0.01f, response)) * deltaTime);
			return current + (target - current) * (float)num;
		}

		internal static float AdvanceTransition(float current, float response, float deltaTime)
		{
			float num = Math.Max(0f, Math.Min(1f, current));
			if (response <= 0f || deltaTime <= 0f)
			{
				return num;
			}
			double num2 = 1.0 - Math.Exp((0f - response) * deltaTime);
			return Math.Max(0f, Math.Min(1f, num + (1f - num) * (float)num2));
		}

		internal static float ClampMagnification(float value, float maximum)
		{
			float val = Math.Max(1f, maximum);
			return Math.Max(1f, Math.Min(val, value));
		}
	}
}