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 _reportedPlugins = new HashSet(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 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 val = default(ConfigEntry); bool flag = instance.Config.TryGetEntry("Map", "MapRangeRBEnabled", ref val); ConfigEntry val2 = default(ConfigEntry); bool flag2 = instance.Config.TryGetEntry("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? _rendererStarted; private static ManualLogSource? _logger; internal static bool Install(Harmony harmony, Action 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 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 _enabled; private readonly ConfigEntry _defaultZoom; private readonly ConfigEntry _minimumZoom; private readonly ConfigEntry _maximumZoom; private readonly ConfigEntry _zoomStep; private readonly ConfigEntry _zoomIn; private readonly ConfigEntry _zoomOut; private readonly ConfigEntry _resetZoom; private readonly ConfigEntry _showZoomNotification; private readonly ConfigEntry _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("General", "Enabled", true, "Enable local ship-radar zoom controls."); _defaultZoom = _configFile.Bind("Radar", "DefaultZoom", 25f, "orthographicSize restored by the reset shortcut. Smaller values appear closer; larger values show more area."); _minimumZoom = _configFile.Bind("Radar", "MinimumZoom", 10f, "Smallest allowed radar-camera orthographicSize."); _maximumZoom = _configFile.Bind("Radar", "MaximumZoom", 60f, "Largest allowed radar-camera orthographicSize."); _zoomStep = _configFile.Bind("Radar", "ZoomStep", 2f, "Amount added or subtracted for each shortcut press."); _zoomIn = _configFile.Bind("Keybinds", "ZoomIn", new KeyboardShortcut((KeyCode)61, Array.Empty()), "Decrease orthographicSize so the radar appears closer."); _zoomOut = _configFile.Bind("Keybinds", "ZoomOut", new KeyboardShortcut((KeyCode)45, Array.Empty()), "Increase orthographicSize so the radar shows a wider area."); _resetZoom = _configFile.Bind("Keybinds", "ResetZoom", new KeyboardShortcut((KeyCode)8, Array.Empty()), "Restore Radar.DefaultZoom."); _showZoomNotification = _configFile.Bind("Display", "ShowZoomNotification", true, "Show a short notification drawn only on this client after a zoom shortcut is used."); _currentZoom = _configFile.Bind("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; } } }