Decompiled source of CommanderRadarZoom v1.0.0

CommanderRadarZoom.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CommanderRadarZoom.Config;
using CommanderRadarZoom.Patches;
using CommanderRadarZoom.Radar;
using CommanderRadarZoom.UI;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("CommanderRadarZoom")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+3beb3e6d2f4e50cd6e70b31043883442a145e919")]
[assembly: AssemblyProduct("CommanderRadarZoom")]
[assembly: AssemblyTitle("CommanderRadarZoom")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CommanderRadarZoom
{
	[BepInPlugin("com.commanderradarzoom.client", "CommanderRadarZoom", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.commanderradarzoom.client";

		public const string PluginName = "CommanderRadarZoom";

		public const string PluginVersion = "1.0.0";

		private Harmony? _harmony;

		private ModConfig? _modConfig;

		private LocalNotification? _notification;

		private RadarZoomController? _radarController;

		private bool _isShuttingDown;

		private bool _updateFailureLogged;

		private bool _guiFailureLogged;

		private void Awake()
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			try
			{
				_modConfig = new ModConfig(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
				_notification = new LocalNotification();
				_radarController = new RadarZoomController(_modConfig, _notification, ((BaseUnityPlugin)this).Logger);
				_radarController.Initialize();
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Unable to initialize the local radar zoom controller. The mod will remain inactive.\n{arg}");
				SafeShutdownController();
				return;
			}
			try
			{
				_harmony = new Harmony("com.commanderradarzoom.client");
				if (!ManualCameraRendererPatch.Install(_harmony, _radarController.OnManualCameraRendererStarted, ((BaseUnityPlugin)this).Logger))
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"ManualCameraRenderer.Start could not be patched. The low-frequency camera discovery fallback will remain available.");
				}
			}
			catch (Exception arg2)
			{
				ManualCameraRendererPatch.Clear();
				((BaseUnityPlugin)this).Logger.LogError((object)("Harmony initialization failed. Radar zoom will continue only through the controller's " + $"safe discovery fallback.\n{arg2}"));
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"CommanderRadarZoom 1.0.0 loaded. Only this client's radar camera rendering is modified.");
		}

		private void Update()
		{
			if (_isShuttingDown || _radarController == null)
			{
				return;
			}
			try
			{
				_radarController.Tick();
				_updateFailureLogged = false;
			}
			catch (Exception arg)
			{
				if (!_updateFailureLogged)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)$"Radar zoom update failed; later frames will retry safely.\n{arg}");
					_updateFailureLogged = true;
				}
			}
		}

		private void OnGUI()
		{
			if (_isShuttingDown || _notification == null)
			{
				return;
			}
			try
			{
				_notification.Draw();
				_guiFailureLogged = false;
			}
			catch (Exception arg)
			{
				if (!_guiFailureLogged)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)$"The local zoom notification could not be drawn.\n{arg}");
					_guiFailureLogged = true;
				}
			}
		}

		private void OnDestroy()
		{
			if (_isShuttingDown)
			{
				return;
			}
			_isShuttingDown = true;
			ManualCameraRendererPatch.Clear();
			SafeShutdownController();
			try
			{
				_notification?.Clear();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to clear the local notification during shutdown: " + ex.Message));
			}
			try
			{
				Harmony? harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to remove Harmony patches during shutdown: " + ex2.Message));
			}
			try
			{
				_modConfig?.Dispose();
			}
			catch (Exception ex3)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to detach configuration handlers during shutdown: " + ex3.Message));
			}
			_radarController = null;
			_notification = null;
			_modConfig = null;
			_harmony = null;
		}

		private void SafeShutdownController()
		{
			try
			{
				_radarController?.Shutdown();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Radar zoom controller shutdown encountered an error: " + ex.Message));
			}
		}
	}
}
namespace CommanderRadarZoom.UI
{
	internal sealed class LocalNotification
	{
		private const float FadeDuration = 0.25f;

		private string? _message;

		private float _expiresAt;

		private GUIStyle? _boxStyle;

		private GUIStyle? _labelStyle;

		internal void Show(string message, float duration = 1.5f)
		{
			if (!string.IsNullOrWhiteSpace(message))
			{
				_message = message;
				_expiresAt = Time.unscaledTime + Mathf.Max(0.1f, duration);
			}
		}

		internal void Clear()
		{
			_message = null;
			_expiresAt = 0f;
		}

		internal void Draw()
		{
			//IL_00e1: 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_0092: 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_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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(_message))
			{
				return;
			}
			float num = _expiresAt - Time.unscaledTime;
			if (num <= 0f)
			{
				Clear();
				return;
			}
			EnsureStyles();
			float num2 = Mathf.Min(360f, Mathf.Max(160f, (float)Screen.width - 20f));
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((float)Screen.width - num2) * 0.5f, 48f, num2, 42f);
			float num3 = ((num < 0.25f) ? Mathf.Clamp01(num / 0.25f) : 1f);
			Color color = GUI.color;
			try
			{
				GUI.color = new Color(color.r, color.g, color.b, color.a * num3);
				GUI.Box(val, GUIContent.none, _boxStyle);
				GUI.Label(val, _message, _labelStyle);
			}
			finally
			{
				GUI.color = color;
			}
		}

		private void EnsureStyles()
		{
			//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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_002e: Expected O, but got Unknown
			//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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0068: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (_boxStyle == null)
			{
				_boxStyle = new GUIStyle(GUI.skin.box)
				{
					padding = new RectOffset(12, 12, 8, 8)
				};
			}
			if (_labelStyle == null)
			{
				_labelStyle = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					fontSize = 18,
					clipping = (TextClipping)1,
					wordWrap = false
				};
				_labelStyle.normal.textColor = new Color(0.62f, 1f, 0.42f, 1f);
			}
		}
	}
}
namespace CommanderRadarZoom.Radar
{
	internal sealed class RadarZoomController
	{
		private const string EnhancedRadarBoosterGuid = "MrHydralisk.EnhancedRadarBooster";

		private const float ReferenceCheckInterval = 1f;

		private const float ZoomEpsilon = 0.001f;

		private readonly ModConfig _config;

		private readonly LocalNotification _notification;

		private readonly ManualLogSource _logger;

		private readonly HashSet<string> _reportedPlugins = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private ManualCameraRenderer? _renderer;

		private Camera? _camera;

		private float _originalZoom;

		private float _lastObservedOrAppliedZoom;

		private float _nextReferenceCheck;

		private bool _initialized;

		private bool _lastEnabledState;

		private bool _compatibilityScanComplete;

		private bool _compatibilityBlocked;

		private bool _cameraBlocked;

		private bool _ownsCurrentValue;

		private bool _lastWriteWasUser;

		private bool _externalChangeLogged;

		private bool _sceneRefreshPending;

		private bool _enhancedRadarBoosterDetected;

		private bool _enhancedInspectionPending;

		private bool _enhancedRuntimeReadFailureLogged;

		private bool _canonicalCameraMismatchLogged;

		private PluginInfo? _enhancedRadarBoosterInfo;

		private FieldInfo? _enhancedRangeEnabledValueField;

		private FieldInfo? _enhancedRangeSyncValueField;

		internal RadarZoomController(ModConfig config, LocalNotification notification, ManualLogSource logger)
		{
			_config = config ?? throw new ArgumentNullException("config");
			_notification = notification ?? throw new ArgumentNullException("notification");
			_logger = logger ?? throw new ArgumentNullException("logger");
		}

		internal void Initialize()
		{
			if (!_initialized)
			{
				SceneManager.sceneLoaded += OnSceneLoaded;
				SceneManager.sceneUnloaded += OnSceneUnloaded;
				_initialized = true;
				_lastEnabledState = _config.Enabled;
				_nextReferenceCheck = 0f;
				_sceneRefreshPending = true;
				_logger.LogInfo((object)($"Configured radar zoom is {_config.CurrentZoom:0.##} " + $"(allowed {_config.MinimumZoom:0.##}-{_config.MaximumZoom:0.##}; larger values show more area)."));
			}
		}

		internal void Tick()
		{
			if (_initialized)
			{
				if (_config.ProcessPendingChanges())
				{
					_sceneRefreshPending = true;
					_nextReferenceCheck = 0f;
				}
				EnsureCompatibilityScan();
				HandleEnabledTransition();
				float unscaledTime = Time.unscaledTime;
				if (unscaledTime >= _nextReferenceCheck)
				{
					_nextReferenceCheck = unscaledTime + 1f;
					RefreshCameraReference();
				}
				if (_config.Enabled && !_compatibilityBlocked && !_cameraBlocked && HasCanonicalCamera() && CanHandleShortcuts())
				{
					ProcessShortcuts();
				}
			}
		}

		internal void OnManualCameraRendererStarted(ManualCameraRenderer renderer)
		{
			if (_initialized && !((Object)(object)renderer == (Object)null))
			{
				EnsureCompatibilityScan();
				TryRegisterCanonicalRenderer(renderer, "ManualCameraRenderer.Start");
			}
		}

		internal void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (_initialized)
			{
				_sceneRefreshPending = true;
				_canonicalCameraMismatchLogged = false;
				_nextReferenceCheck = 0f;
			}
		}

		internal void OnSceneUnloaded(Scene scene)
		{
			if (_initialized)
			{
				_sceneRefreshPending = true;
				_canonicalCameraMismatchLogged = false;
				_nextReferenceCheck = 0f;
			}
		}

		internal void Shutdown()
		{
			if (_initialized)
			{
				SceneManager.sceneLoaded -= OnSceneLoaded;
				SceneManager.sceneUnloaded -= OnSceneUnloaded;
				TryRestoreOriginalZoom("plugin shutdown");
				ClearCameraReference();
				_initialized = false;
			}
		}

		private void HandleEnabledTransition()
		{
			bool enabled = _config.Enabled;
			if (enabled != _lastEnabledState)
			{
				_lastEnabledState = enabled;
				if (!enabled)
				{
					TryRestoreOriginalZoom("the mod was disabled");
					_notification.Clear();
					_logger.LogInfo((object)"Radar zoom handling is disabled.");
				}
				else
				{
					_logger.LogInfo((object)"Radar zoom handling is enabled.");
					_sceneRefreshPending = true;
					_nextReferenceCheck = 0f;
				}
			}
		}

		private void RefreshCameraReference()
		{
			CheckEnhancedRadarBoosterRuntimeState();
			if (!HasCanonicalCamera())
			{
				ReleaseCameraReference();
				TryAcquireCanonicalRenderer();
				return;
			}
			if (_sceneRefreshPending)
			{
				_sceneRefreshPending = false;
				if (_config.Enabled && !_compatibilityBlocked && !_cameraBlocked)
				{
					ApplyZoom(_config.CurrentZoom, "scene, round, or configuration refresh", persist: false, notify: false, userInitiated: false);
				}
			}
			ObserveExternalChanges();
		}

		private void TryAcquireCanonicalRenderer()
		{
			StartOfRound instance = StartOfRound.Instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.mapScreen == (Object)null))
			{
				TryRegisterCanonicalRenderer(instance.mapScreen, "low-frequency discovery");
			}
		}

		private void TryRegisterCanonicalRenderer(ManualCameraRenderer renderer, string source)
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.mapScreen == (Object)null || (Object)(object)renderer != (Object)(object)instance.mapScreen)
			{
				return;
			}
			Camera mapCamera = renderer.mapCamera;
			if ((Object)(object)mapCamera == (Object)null || (Object)(object)renderer.cam == (Object)null || (Object)(object)renderer.cam != (Object)(object)mapCamera)
			{
				if (!_canonicalCameraMismatchLogged)
				{
					_canonicalCameraMismatchLogged = true;
					_logger.LogWarning((object)("The canonical mapScreen found through " + source + " does not currently expose the same Camera through both cam and mapCamera. No camera value will be changed; discovery will retry at low frequency."));
				}
			}
			else
			{
				if ((Object)(object)_renderer == (Object)(object)renderer && (Object)(object)_camera == (Object)(object)mapCamera)
				{
					return;
				}
				ReleaseCameraReference();
				_renderer = renderer;
				_camera = mapCamera;
				_originalZoom = mapCamera.orthographicSize;
				_lastObservedOrAppliedZoom = _originalZoom;
				_cameraBlocked = false;
				_ownsCurrentValue = false;
				_lastWriteWasUser = false;
				_externalChangeLogged = false;
				_canonicalCameraMismatchLogged = false;
				_sceneRefreshPending = false;
				if (!mapCamera.orthographic)
				{
					_cameraBlocked = true;
					_logger.LogWarning((object)("The canonical radar camera found through " + source + " is not orthographic. CommanderRadarZoom will not force a projection change; zoom is disabled for this camera."));
					return;
				}
				_logger.LogInfo((object)$"Cached the canonical local ship radar camera through {source}; native orthographicSize is {_originalZoom:0.##}.");
				if (_config.Enabled && !_compatibilityBlocked)
				{
					ApplyZoom(_config.CurrentZoom, "camera initialization", persist: false, notify: false, userInitiated: false);
				}
			}
		}

		private void ProcessShortcuts()
		{
			//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_0035: 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_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)
			KeyboardShortcut val = _config.ResetZoom;
			if (((KeyboardShortcut)(ref val)).IsDown())
			{
				ApplyZoom(_config.DefaultZoom, "reset", persist: true, notify: true, userInitiated: true);
				return;
			}
			val = _config.ZoomIn;
			if (((KeyboardShortcut)(ref val)).IsDown())
			{
				float currentCameraZoomAsBaseline = GetCurrentCameraZoomAsBaseline();
				ApplyZoom(currentCameraZoomAsBaseline - _config.ZoomStep, "zoom in", persist: true, notify: true, userInitiated: true);
				return;
			}
			val = _config.ZoomOut;
			if (((KeyboardShortcut)(ref val)).IsDown())
			{
				float currentCameraZoomAsBaseline2 = GetCurrentCameraZoomAsBaseline();
				ApplyZoom(currentCameraZoomAsBaseline2 + _config.ZoomStep, "zoom out", persist: true, notify: true, userInitiated: true);
			}
		}

		private float GetCurrentCameraZoomAsBaseline()
		{
			if ((Object)(object)_camera == (Object)null)
			{
				return _config.CurrentZoom;
			}
			float orthographicSize = _camera.orthographicSize;
			if (!Approximately(orthographicSize, _lastObservedOrAppliedZoom))
			{
				ReconcileObservedZoom(orthographicSize);
			}
			return _config.ClampZoom(orthographicSize);
		}

		private void ApplyZoom(float requested, string reason, bool persist, bool notify, bool userInitiated)
		{
			if ((Object)(object)_camera == (Object)null || _cameraBlocked || _compatibilityBlocked)
			{
				return;
			}
			float orthographicSize = _camera.orthographicSize;
			if (!Approximately(orthographicSize, _lastObservedOrAppliedZoom) && !ReconcileObservedZoom(orthographicSize))
			{
				return;
			}
			if (!_camera.orthographic)
			{
				TryRestoreOriginalZoom("the canonical radar camera changed to a perspective projection");
				_cameraBlocked = true;
				_logger.LogWarning((object)"The canonical radar camera changed to a perspective projection. Zoom has been disabled for this camera.");
				return;
			}
			float num = _config.ClampZoom(requested);
			if (!Approximately(orthographicSize, num))
			{
				_camera.orthographicSize = num;
				_ownsCurrentValue = true;
				_lastWriteWasUser = userInitiated;
			}
			else if (userInitiated && _ownsCurrentValue)
			{
				_lastWriteWasUser = true;
			}
			_lastObservedOrAppliedZoom = num;
			if (persist)
			{
				_config.SetCurrentZoom(num);
			}
			_logger.LogInfo((object)$"Radar zoom: {num:0.##} ({reason}).");
			if (notify && _config.ShowZoomNotification)
			{
				_notification.Show($"Radar zoom: {num:0.##}");
			}
		}

		private void ObserveExternalChanges()
		{
			if ((Object)(object)_camera == (Object)null || !_config.Enabled || _compatibilityBlocked || _cameraBlocked)
			{
				return;
			}
			if (!_camera.orthographic)
			{
				TryRestoreOriginalZoom("the canonical radar camera changed to a perspective projection");
				_cameraBlocked = true;
				_logger.LogWarning((object)"The canonical radar camera changed to a perspective projection. Zoom has been disabled for this camera.");
				return;
			}
			float orthographicSize = _camera.orthographicSize;
			if (!Approximately(orthographicSize, _lastObservedOrAppliedZoom))
			{
				ReconcileObservedZoom(orthographicSize);
			}
		}

		private bool ReconcileObservedZoom(float actual)
		{
			if (_ownsCurrentValue && _lastWriteWasUser)
			{
				_ownsCurrentValue = false;
				_lastWriteWasUser = false;
				_cameraBlocked = true;
				_logger.LogWarning((object)("Another mod changed the radar orthographicSize from the requested " + $"{_lastObservedOrAppliedZoom:0.##} to {actual:0.##}. " + "CommanderRadarZoom has stopped writing to this camera to avoid a per-frame conflict."));
				return false;
			}
			AdoptExternalBaseline(actual);
			return true;
		}

		private void AdoptExternalBaseline(float actual)
		{
			_lastObservedOrAppliedZoom = actual;
			_ownsCurrentValue = false;
			_lastWriteWasUser = false;
			if (!_externalChangeLogged)
			{
				_externalChangeLogged = true;
				_logger.LogWarning((object)($"Observed an external radar zoom value of {actual:0.##}. It will be respected; " + "CommanderRadarZoom will write again only after a user shortcut or lifecycle refresh."));
			}
		}

		private bool CanHandleShortcuts()
		{
			if (!Application.isFocused)
			{
				return false;
			}
			GameNetworkManager instance = GameNetworkManager.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.localPlayerController == (Object)null)
			{
				return false;
			}
			PlayerControllerB localPlayerController = instance.localPlayerController;
			if (!localPlayerController.isPlayerControlled || localPlayerController.isTypingChat || localPlayerController.inTerminalMenu || localPlayerController.inSpecialMenu)
			{
				return false;
			}
			if (!((Object)(object)localPlayerController.quickMenuManager == (Object)null))
			{
				return !localPlayerController.quickMenuManager.isMenuOpen;
			}
			return true;
		}

		private bool HasCanonicalCamera()
		{
			if ((Object)(object)_renderer == (Object)null || (Object)(object)_camera == (Object)null)
			{
				return false;
			}
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)instance.mapScreen != (Object)null && (Object)(object)instance.mapScreen == (Object)(object)_renderer && (Object)(object)_renderer.mapCamera == (Object)(object)_camera)
			{
				return (Object)(object)_renderer.cam == (Object)(object)_camera;
			}
			return false;
		}

		private void ReleaseCameraReference()
		{
			bool flag = (Object)(object)_renderer != (Object)null || (Object)(object)_camera != (Object)null;
			TryRestoreOriginalZoom("the radar camera reference changed");
			ClearCameraReference();
			if (flag)
			{
				_canonicalCameraMismatchLogged = false;
			}
		}

		private void TryRestoreOriginalZoom(string reason)
		{
			if ((Object)(object)_camera == (Object)null || !_ownsCurrentValue)
			{
				_ownsCurrentValue = false;
				_lastWriteWasUser = false;
				return;
			}
			float orthographicSize = _camera.orthographicSize;
			if (!Approximately(orthographicSize, _lastObservedOrAppliedZoom))
			{
				_logger.LogWarning((object)("The radar camera no longer contains CommanderRadarZoom's last value while " + reason + "; the external value was left unchanged."));
				_ownsCurrentValue = false;
				_lastWriteWasUser = false;
			}
			else
			{
				_camera.orthographicSize = _originalZoom;
				_logger.LogInfo((object)$"Restored native radar zoom {_originalZoom:0.##} because {reason}.");
				_ownsCurrentValue = false;
				_lastWriteWasUser = false;
				_lastObservedOrAppliedZoom = _originalZoom;
			}
		}

		private void ClearCameraReference()
		{
			_renderer = null;
			_camera = null;
			_cameraBlocked = false;
			_ownsCurrentValue = false;
			_lastWriteWasUser = false;
			_externalChangeLogged = false;
			_originalZoom = 0f;
			_lastObservedOrAppliedZoom = 0f;
		}

		private void EnsureCompatibilityScan()
		{
			if (_compatibilityScanComplete)
			{
				return;
			}
			_compatibilityScanComplete = true;
			try
			{
				ScanInstalledPlugins();
			}
			catch (Exception ex)
			{
				_logger.LogWarning((object)("Could not complete the one-time radar-mod compatibility scan. Runtime value observation remains active: " + ex.Message));
			}
		}

		private void ScanInstalledPlugins()
		{
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				PluginInfo value = pluginInfo.Value;
				BepInPlugin metadata = value.Metadata;
				string text = ((metadata != null) ? metadata.GUID : null) ?? pluginInfo.Key;
				BepInPlugin metadata2 = value.Metadata;
				string name = ((metadata2 != null) ? metadata2.Name : null) ?? string.Empty;
				string fileName = (string.IsNullOrEmpty(value.Location) ? string.Empty : Path.GetFileNameWithoutExtension(value.Location));
				if (string.Equals(text, "MrHydralisk.EnhancedRadarBooster", StringComparison.OrdinalIgnoreCase))
				{
					InspectEnhancedRadarBooster(value);
				}
				else if (MatchesRadarModToken(text, name, fileName))
				{
					ReportPotentialRadarMod(text, name);
				}
			}
		}

		private void InspectEnhancedRadarBooster(PluginInfo info)
		{
			_enhancedRadarBoosterDetected = true;
			_enhancedRadarBoosterInfo = info;
			BaseUnityPlugin instance = info.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				_enhancedInspectionPending = true;
				_logger.LogWarning((object)"EnhancedRadarBooster was detected, but its configuration was unavailable. Its state will be checked again after plugin initialization; runtime overwrite detection also remains active.");
				return;
			}
			_enhancedInspectionPending = false;
			Type type = ((object)instance).GetType().Assembly.GetType("EnhancedRadarBooster.Config", throwOnError: false);
			if (type != null)
			{
				_enhancedRangeEnabledValueField = type.GetField("mapRangeRBEnabledValue", BindingFlags.Static | BindingFlags.Public);
				_enhancedRangeSyncValueField = type.GetField("mapRangeRBSyncValue", BindingFlags.Static | BindingFlags.Public);
			}
			ConfigEntry<bool> val = default(ConfigEntry<bool>);
			bool flag = instance.Config.TryGetEntry<bool>("Map", "MapRangeRBEnabled", ref val);
			ConfigEntry<bool> val2 = default(ConfigEntry<bool>);
			bool flag2 = instance.Config.TryGetEntry<bool>("Map", "MapRangeRBSync", ref val2);
			bool flag3 = flag && val.Value;
			bool flag4 = flag2 && val2.Value;
			bool conflictActive;
			bool flag5 = TryReadEnhancedRadarBoosterRuntimeState(out conflictActive);
			if (flag3 || flag4 || (flag5 && conflictActive))
			{
				BlockForEnhancedRadarBooster();
			}
			else if (!flag && !flag2)
			{
				_logger.LogWarning((object)"EnhancedRadarBooster was detected, but its map-range settings could not be read. Runtime overwrite detection will remain active.");
			}
			else
			{
				_logger.LogInfo((object)"EnhancedRadarBooster was detected with its conflicting map-range options disabled.");
			}
		}

		private void CheckEnhancedRadarBoosterRuntimeState()
		{
			if (!_enhancedRadarBoosterDetected || _compatibilityBlocked)
			{
				return;
			}
			if (_enhancedInspectionPending)
			{
				PluginInfo? enhancedRadarBoosterInfo = _enhancedRadarBoosterInfo;
				if ((Object)(object)((enhancedRadarBoosterInfo != null) ? enhancedRadarBoosterInfo.Instance : null) != (Object)null)
				{
					InspectEnhancedRadarBooster(_enhancedRadarBoosterInfo);
					if (_compatibilityBlocked)
					{
						return;
					}
				}
			}
			if (TryReadEnhancedRadarBoosterRuntimeState(out var conflictActive) && conflictActive)
			{
				BlockForEnhancedRadarBooster();
			}
		}

		private bool TryReadEnhancedRadarBoosterRuntimeState(out bool conflictActive)
		{
			conflictActive = false;
			bool result = false;
			try
			{
				if (_enhancedRangeEnabledValueField?.GetValue(null) is bool flag)
				{
					result = true;
					conflictActive |= flag;
				}
				if (_enhancedRangeSyncValueField?.GetValue(null) is bool flag2)
				{
					result = true;
					conflictActive |= flag2;
				}
				return result;
			}
			catch (Exception ex)
			{
				if (!_enhancedRuntimeReadFailureLogged)
				{
					_enhancedRuntimeReadFailureLogged = true;
					_logger.LogWarning((object)("EnhancedRadarBooster runtime map-range state could not be read. Camera overwrite observation remains active: " + ex.Message));
				}
				return false;
			}
		}

		private void BlockForEnhancedRadarBooster()
		{
			if (!_compatibilityBlocked)
			{
				_compatibilityBlocked = true;
				TryRestoreOriginalZoom("EnhancedRadarBooster controls the same property");
				_notification.Clear();
				_logger.LogWarning((object)"CommanderRadarZoom camera writes are disabled because EnhancedRadarBooster controls orthographicSize. Set [Map] MapRangeRBEnabled=false and MapRangeRBSync=false in that mod, then reconnect or restart. If those values are host-synchronized, the controlling host's EnhancedRadarBooster configuration must be changed.");
			}
		}

		private void ReportPotentialRadarMod(string guid, string name)
		{
			if (_reportedPlugins.Add(guid))
			{
				_logger.LogInfo((object)("Detected radar/camera-related plugin '" + name + "' (" + guid + "). Only the canonical ship radar camera will be modified; runtime conflicts are observed without continuous overwrites."));
			}
		}

		private static bool MatchesRadarModToken(string guid, string name, string fileName)
		{
			string text = guid + " " + name + " " + fileName;
			if (text.IndexOf("Minimap", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("TwoRadarMaps", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("GeneralImprovements", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("ShipWindows", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return text.IndexOf("OpenBodyCams", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static bool Approximately(float left, float right)
		{
			return Math.Abs(left - right) <= 0.001f;
		}
	}
}
namespace CommanderRadarZoom.Patches
{
	internal static class ManualCameraRendererPatch
	{
		private static Action<ManualCameraRenderer>? _rendererStarted;

		private static ManualLogSource? _logger;

		internal static bool Install(Harmony harmony, Action<ManualCameraRenderer> rendererStarted, ManualLogSource logger)
		{
			//IL_00b1: 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_00be: Expected O, but got Unknown
			if (harmony == null)
			{
				throw new ArgumentNullException("harmony");
			}
			if (rendererStarted == null)
			{
				throw new ArgumentNullException("rendererStarted");
			}
			if (logger == null)
			{
				throw new ArgumentNullException("logger");
			}
			MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ManualCameraRenderer), "Start", Type.EmptyTypes, (Type[])null);
			if (methodInfo == null)
			{
				logger.LogError((object)"ManualCameraRenderer.Start() was not found in the current game assembly; the initialization patch has been disabled.");
				Clear();
				return false;
			}
			MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(ManualCameraRendererPatch), "StartPostfix", new Type[1] { typeof(ManualCameraRenderer) }, (Type[])null);
			if (methodInfo2 == null)
			{
				logger.LogError((object)"The internal ManualCameraRenderer postfix bridge could not be located.");
				Clear();
				return false;
			}
			_rendererStarted = rendererStarted;
			_logger = logger;
			try
			{
				HarmonyMethod val = new HarmonyMethod(methodInfo2)
				{
					priority = 0
				};
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				logger.LogInfo((object)"Patched ManualCameraRenderer.Start() with a Priority.Last postfix for local radar camera discovery.");
				return true;
			}
			catch (Exception ex)
			{
				logger.LogError((object)("ManualCameraRenderer.Start() could not be patched; the patch path is disabled.\n" + ex));
				Clear();
				return false;
			}
		}

		internal static void Clear()
		{
			_rendererStarted = null;
			_logger = null;
		}

		[HarmonyPriority(0)]
		private static void StartPostfix(ManualCameraRenderer __instance)
		{
			Action<ManualCameraRenderer> rendererStarted = _rendererStarted;
			if (rendererStarted == null || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			try
			{
				rendererStarted(__instance);
			}
			catch (Exception arg)
			{
				try
				{
					ManualLogSource? logger = _logger;
					if (logger != null)
					{
						logger.LogError((object)("An exception occurred while processing the local radar renderer initialization. " + $"The game will continue normally.\n{arg}"));
					}
				}
				catch
				{
				}
			}
		}
	}
}
namespace CommanderRadarZoom.Config
{
	internal sealed class ModConfig : IDisposable
	{
		private const float DefaultDefaultZoom = 25f;

		private const float DefaultMinimumZoom = 10f;

		private const float DefaultMaximumZoom = 60f;

		private const float DefaultZoomStep = 2f;

		private readonly ConfigFile _configFile;

		private readonly ManualLogSource _logger;

		private readonly ConfigEntry<bool> _enabled;

		private readonly ConfigEntry<float> _defaultZoom;

		private readonly ConfigEntry<float> _minimumZoom;

		private readonly ConfigEntry<float> _maximumZoom;

		private readonly ConfigEntry<float> _zoomStep;

		private readonly ConfigEntry<KeyboardShortcut> _zoomIn;

		private readonly ConfigEntry<KeyboardShortcut> _zoomOut;

		private readonly ConfigEntry<KeyboardShortcut> _resetZoom;

		private readonly ConfigEntry<bool> _showZoomNotification;

		private readonly ConfigEntry<float> _currentZoom;

		private bool _handlingSettingChange;

		private bool _validationPending;

		private bool _shortcutWarningPending;

		private bool _savePending;

		private bool _disposed;

		internal bool Enabled => _enabled.Value;

		internal float DefaultZoom => _defaultZoom.Value;

		internal float MinimumZoom => _minimumZoom.Value;

		internal float MaximumZoom => _maximumZoom.Value;

		internal float ZoomStep => _zoomStep.Value;

		internal KeyboardShortcut ZoomIn => _zoomIn.Value;

		internal KeyboardShortcut ZoomOut => _zoomOut.Value;

		internal KeyboardShortcut ResetZoom => _resetZoom.Value;

		internal bool ShowZoomNotification => _showZoomNotification.Value;

		internal float CurrentZoom => _currentZoom.Value;

		internal ModConfig(ConfigFile configFile, ManualLogSource logger)
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			_configFile = configFile ?? throw new ArgumentNullException("configFile");
			_logger = logger ?? throw new ArgumentNullException("logger");
			_configFile.SaveOnConfigSet = false;
			_enabled = _configFile.Bind<bool>("General", "Enabled", true, "Enable local ship-radar zoom controls.");
			_defaultZoom = _configFile.Bind<float>("Radar", "DefaultZoom", 25f, "orthographicSize restored by the reset shortcut. Smaller values appear closer; larger values show more area.");
			_minimumZoom = _configFile.Bind<float>("Radar", "MinimumZoom", 10f, "Smallest allowed radar-camera orthographicSize.");
			_maximumZoom = _configFile.Bind<float>("Radar", "MaximumZoom", 60f, "Largest allowed radar-camera orthographicSize.");
			_zoomStep = _configFile.Bind<float>("Radar", "ZoomStep", 2f, "Amount added or subtracted for each shortcut press.");
			_zoomIn = _configFile.Bind<KeyboardShortcut>("Keybinds", "ZoomIn", new KeyboardShortcut((KeyCode)61, Array.Empty<KeyCode>()), "Decrease orthographicSize so the radar appears closer.");
			_zoomOut = _configFile.Bind<KeyboardShortcut>("Keybinds", "ZoomOut", new KeyboardShortcut((KeyCode)45, Array.Empty<KeyCode>()), "Increase orthographicSize so the radar shows a wider area.");
			_resetZoom = _configFile.Bind<KeyboardShortcut>("Keybinds", "ResetZoom", new KeyboardShortcut((KeyCode)8, Array.Empty<KeyCode>()), "Restore Radar.DefaultZoom.");
			_showZoomNotification = _configFile.Bind<bool>("Display", "ShowZoomNotification", true, "Show a short notification drawn only on this client after a zoom shortcut is used.");
			_currentZoom = _configFile.Bind<float>("State", "CurrentZoom", 25f, "Last user-selected zoom. This value is maintained by the plugin and restored on the next launch.");
			ValidateAndSave();
			WarnAboutShortcutCollisions();
			SubscribeToSettingChanges();
		}

		internal float ClampZoom(float value)
		{
			if (!IsFinite(value))
			{
				value = DefaultZoom;
			}
			return Mathf.Clamp(value, MinimumZoom, MaximumZoom);
		}

		internal void SetCurrentZoom(float value)
		{
			float num = ClampZoom(value);
			if (!Approximately(_currentZoom.Value, num))
			{
				_handlingSettingChange = true;
				try
				{
					_currentZoom.Value = num;
				}
				finally
				{
					_handlingSettingChange = false;
				}
				TrySave("current radar zoom");
			}
		}

		internal bool ProcessPendingChanges()
		{
			if (_disposed || _handlingSettingChange)
			{
				return false;
			}
			bool validationPending = _validationPending;
			bool shortcutWarningPending = _shortcutWarningPending;
			bool savePending = _savePending;
			if (!validationPending && !shortcutWarningPending && !savePending)
			{
				return false;
			}
			_validationPending = false;
			_shortcutWarningPending = false;
			_savePending = false;
			_handlingSettingChange = true;
			bool flag = false;
			try
			{
				if (validationPending)
				{
					ValidateAndSave();
					flag = true;
				}
				else if (savePending)
				{
					TrySave("configuration change");
				}
				if (shortcutWarningPending)
				{
					WarnAboutShortcutCollisions();
				}
			}
			catch (Exception arg)
			{
				_logger.LogError((object)$"Could not process a runtime configuration change safely: {arg}");
			}
			finally
			{
				_handlingSettingChange = false;
			}
			return validationPending && flag;
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				_enabled.SettingChanged -= OnSimpleSettingChanged;
				_showZoomNotification.SettingChanged -= OnSimpleSettingChanged;
				_defaultZoom.SettingChanged -= OnValidatedSettingChanged;
				_minimumZoom.SettingChanged -= OnValidatedSettingChanged;
				_maximumZoom.SettingChanged -= OnValidatedSettingChanged;
				_zoomStep.SettingChanged -= OnValidatedSettingChanged;
				_currentZoom.SettingChanged -= OnValidatedSettingChanged;
				_zoomIn.SettingChanged -= OnShortcutSettingChanged;
				_zoomOut.SettingChanged -= OnShortcutSettingChanged;
				_resetZoom.SettingChanged -= OnShortcutSettingChanged;
			}
		}

		private void SubscribeToSettingChanges()
		{
			_enabled.SettingChanged += OnSimpleSettingChanged;
			_showZoomNotification.SettingChanged += OnSimpleSettingChanged;
			_defaultZoom.SettingChanged += OnValidatedSettingChanged;
			_minimumZoom.SettingChanged += OnValidatedSettingChanged;
			_maximumZoom.SettingChanged += OnValidatedSettingChanged;
			_zoomStep.SettingChanged += OnValidatedSettingChanged;
			_currentZoom.SettingChanged += OnValidatedSettingChanged;
			_zoomIn.SettingChanged += OnShortcutSettingChanged;
			_zoomOut.SettingChanged += OnShortcutSettingChanged;
			_resetZoom.SettingChanged += OnShortcutSettingChanged;
		}

		private void OnSimpleSettingChanged(object sender, EventArgs eventArgs)
		{
			if (!_disposed && !_handlingSettingChange)
			{
				_savePending = true;
			}
		}

		private void OnValidatedSettingChanged(object sender, EventArgs eventArgs)
		{
			if (!_disposed && !_handlingSettingChange)
			{
				_validationPending = true;
				_savePending = true;
			}
		}

		private void OnShortcutSettingChanged(object sender, EventArgs eventArgs)
		{
			if (!_disposed && !_handlingSettingChange)
			{
				_shortcutWarningPending = true;
				_savePending = true;
			}
		}

		private void ValidateAndSave()
		{
			float num = _minimumZoom.Value;
			if (!IsFinite(num) || num <= 0f)
			{
				WarnCorrection("Radar.MinimumZoom", num, 10f);
				num = 10f;
			}
			float num2 = _maximumZoom.Value;
			if (!IsFinite(num2) || num2 <= 0f)
			{
				WarnCorrection("Radar.MaximumZoom", num2, 60f);
				num2 = 60f;
			}
			if (num > num2)
			{
				_logger.LogWarning((object)$"Radar.MinimumZoom ({num}) was greater than Radar.MaximumZoom ({num2}); the values were swapped.");
				float num3 = num;
				num = num2;
				num2 = num3;
			}
			_minimumZoom.Value = num;
			_maximumZoom.Value = num2;
			float num4 = _defaultZoom.Value;
			if (!IsFinite(num4) || num4 <= 0f)
			{
				WarnCorrection("Radar.DefaultZoom", num4, 25f);
				num4 = 25f;
			}
			float num5 = Mathf.Clamp(num4, num, num2);
			if (!Approximately(num4, num5))
			{
				WarnCorrection("Radar.DefaultZoom", num4, num5);
			}
			_defaultZoom.Value = num5;
			float num6 = _zoomStep.Value;
			if (!IsFinite(num6) || num6 <= 0f)
			{
				WarnCorrection("Radar.ZoomStep", num6, 2f);
				num6 = 2f;
			}
			_zoomStep.Value = num6;
			float num7 = _currentZoom.Value;
			if (!IsFinite(num7) || num7 <= 0f)
			{
				WarnCorrection("State.CurrentZoom", num7, num5);
				num7 = num5;
			}
			float num8 = Mathf.Clamp(num7, num, num2);
			if (!Approximately(num7, num8))
			{
				WarnCorrection("State.CurrentZoom", num7, num8);
			}
			_currentZoom.Value = num8;
			TrySave("validated configuration");
		}

		private void WarnAboutShortcutCollisions()
		{
			//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_0014: 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_0046: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if (((object)_resetZoom.Value/*cast due to .constrained prefix*/).Equals((object?)_zoomIn.Value))
			{
				_logger.LogWarning((object)"Keybinds.ResetZoom and Keybinds.ZoomIn are identical. ResetZoom takes precedence.");
			}
			if (((object)_resetZoom.Value/*cast due to .constrained prefix*/).Equals((object?)_zoomOut.Value))
			{
				_logger.LogWarning((object)"Keybinds.ResetZoom and Keybinds.ZoomOut are identical. ResetZoom takes precedence.");
			}
			if (((object)_zoomIn.Value/*cast due to .constrained prefix*/).Equals((object?)_zoomOut.Value))
			{
				_logger.LogWarning((object)"Keybinds.ZoomIn and Keybinds.ZoomOut are identical. ZoomIn takes precedence.");
			}
		}

		private void WarnCorrection(string setting, float previous, float corrected)
		{
			_logger.LogWarning((object)$"Invalid {setting} value '{previous}' was corrected to '{corrected}'.");
		}

		private void TrySave(string reason)
		{
			try
			{
				_configFile.Save();
			}
			catch (Exception arg)
			{
				_logger.LogError((object)$"Could not save {reason} to '{_configFile.ConfigFilePath}': {arg}");
			}
		}

		private static bool IsFinite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		private static bool Approximately(float left, float right)
		{
			return Math.Abs(left - right) <= 0.0001f;
		}
	}
}