Decompiled source of ConcernedCartographer v0.10.0

plugins/TheConcernedCat.ConcernedCartographer.dll

Decompiled 8 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using Splatform;
using TheConcernedCat.ConcernedCartographer.Atlas;
using TheConcernedCat.ConcernedCartographer.Map;
using TheConcernedCat.ConcernedCartographer.Persistence;
using TheConcernedCat.ConcernedCartographer.Reporting;
using TheConcernedCat.ConcernedCartographer.Roads;
using TheConcernedCat.ConcernedCartographer.Runtime;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("The Concerned Cat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2026 Eren Cansunar")]
[assembly: AssemblyFileVersion("0.10.0.0")]
[assembly: AssemblyInformationalVersion("0.10.0+a23bef007a75b84282c3aa0e0043b9be468f3301")]
[assembly: AssemblyProduct("Concerned Cartographer")]
[assembly: AssemblyTitle("TheConcernedCat.ConcernedCartographer")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Weakened/ConcernedCatMods")]
[assembly: AssemblyVersion("0.10.0.0")]
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;
		}
	}
}
namespace TheConcernedCat.ConcernedCartographer
{
	[BepInPlugin("com.theconcernedcat.valheim.concernedcartographer", "Concerned Cartographer", "0.10.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.theconcernedcat.valheim.concernedcartographer";

		public const string PluginName = "Concerned Cartographer";

		public const string PluginVersion = "0.10.0";

		private CartographerRuntime? _runtime;

		private CrashReportingHub? _crashHub;

		private void Awake()
		{
			CartographerSettings settings = CartographerSettings.Bind(((BaseUnityPlugin)this).Config);
			LocalizationPersistence.Initialize(((BaseUnityPlugin)this).Logger);
			try
			{
				_crashHub = new CrashReportingHub(settings, BuildCrashContext());
				_crashHub.Attach(((BaseUnityPlugin)this).Logger);
			}
			catch (Exception exception)
			{
				_crashHub = null;
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Crash reporting unavailable this session: " + SafeLogText.Brief(exception)));
			}
			_runtime = new CartographerRuntime(settings, ((BaseUnityPlugin)this).Logger);
			MinimapManager.OnVanillaMapAvailable += HandleMapAvailable;
			MinimapManager.OnVanillaMapDataLoaded += HandleMapDataLoaded;
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new RoadToolsCommand(_runtime));
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new PinToolsCommand(_runtime));
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new AtlasToolsCommand(_runtime));
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new SurveyToolsCommand(_runtime));
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new RouteToolsCommand(_runtime));
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new SyncToolsCommand(_runtime));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Concerned Cartographer 0.10.0 loaded");
			LogEnvironment(settings);
		}

		private static string ResolveInformationalVersion()
		{
			try
			{
				return typeof(Plugin).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? "0.10.0";
			}
			catch
			{
				return "0.10.0";
			}
		}

		private CrashReportContext BuildCrashContext()
		{
			string text = ResolveInformationalVersion();
			string bepInExVersion = "unknown";
			string jotunnVersion = "unknown";
			try
			{
				bepInExVersion = typeof(BaseUnityPlugin).Assembly.GetName().Version?.ToString() ?? "unknown";
				jotunnVersion = typeof(Main).Assembly.GetName().Version?.ToString() ?? "unknown";
			}
			catch
			{
			}
			return new CrashReportContext
			{
				Release = "ConcernedCartographer@" + text,
				ModVersion = "0.10.0",
				ValheimVersion = ResolveGameVersion(),
				UnityVersion = Application.unityVersion,
				BepInExVersion = bepInExVersion,
				JotunnVersion = jotunnVersion,
				RuntimeState = SampleRuntimeState
			};
		}

		private static CrashReportRuntimeState SampleRuntimeState()
		{
			bool multiplayer = false;
			bool noMap = false;
			bool mapOpen = false;
			try
			{
				multiplayer = (Object)(object)ZNet.instance != (Object)null && ZNet.instance.GetPeers().Count > 0;
			}
			catch
			{
			}
			try
			{
				noMap = (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey("nomap");
			}
			catch
			{
			}
			try
			{
				mapOpen = Minimap.IsOpen();
			}
			catch
			{
			}
			return new CrashReportRuntimeState(multiplayer, noMap, mapOpen);
		}

		private void LogEnvironment(CartographerSettings settings)
		{
			try
			{
				string text = typeof(BaseUnityPlugin).Assembly.GetName().Version?.ToString() ?? "unknown";
				string text2 = typeof(Main).Assembly.GetName().Version?.ToString() ?? "unknown";
				string text3 = ResolveGameVersion();
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Environment: Valheim " + text3 + ", Unity " + Application.unityVersion + ", BepInEx " + text + ", Jotunn " + text2 + "."));
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Release: ConcernedCartographer@" + ResolveInformationalVersion() + "."));
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Effective config (out-of-range values are clamped to documented ranges): " + $"Enabled={settings.Enabled.Value}, " + $"CaptureConstructionActions={settings.CaptureConstructionActions.Value}, " + $"ReconcileTerrainChanges={settings.ReconcileTerrainChanges.Value}, " + $"SampleIntervalSeconds={settings.SampleIntervalSeconds.Value}, " + $"MinimumPointSpacingMeters={settings.MinimumPointSpacingMeters.Value}, " + $"MaximumStrokeGapMeters={settings.MaximumStrokeGapMeters.Value}, " + $"DuplicateSuppressionMeters={settings.DuplicateSuppressionMeters.Value}, " + $"AutosaveIntervalSeconds={settings.AutosaveIntervalSeconds.Value}, " + $"PaintThreshold={settings.PaintThreshold.Value}, " + $"PaintSampleRadius={settings.PaintSampleRadius.Value}, " + $"LineWidthPixels={settings.LineWidthPixels.Value}, " + $"DebugLogging={settings.DebugLogging.Value}, " + $"DrawCalibrationMarkers={settings.DrawCalibrationMarkers.Value}."));
			}
			catch (Exception exception)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not record environment versions: " + SafeLogText.Brief(exception)));
			}
		}

		private static string ResolveGameVersion()
		{
			try
			{
				Type typeFromHandle = typeof(Version);
				object obj = typeFromHandle.GetField("CurrentVersion", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) ?? typeFromHandle.GetProperty("CurrentVersion", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj != null)
				{
					return obj.ToString();
				}
				MethodInfo[] methods = typeFromHandle.GetMethods(BindingFlags.Static | BindingFlags.Public);
				foreach (MethodInfo methodInfo in methods)
				{
					if (!(methodInfo.Name != "GetVersionString") && !(methodInfo.ReturnType != typeof(string)))
					{
						ParameterInfo[] parameters = methodInfo.GetParameters();
						object[] array = new object[parameters.Length];
						for (int j = 0; j < parameters.Length; j++)
						{
							array[j] = (parameters[j].HasDefaultValue ? parameters[j].DefaultValue : (parameters[j].ParameterType.IsValueType ? Activator.CreateInstance(parameters[j].ParameterType) : null));
						}
						return (methodInfo.Invoke(null, array) as string) ?? "unknown";
					}
				}
			}
			catch
			{
			}
			return "unknown";
		}

		private void HandleMapAvailable()
		{
			_runtime?.OnMapAvailable();
		}

		private void HandleMapDataLoaded()
		{
			_runtime?.OnMapDataReconstructed();
		}

		private void Update()
		{
			_runtime?.Tick(Time.unscaledDeltaTime);
		}

		private void OnApplicationQuit()
		{
			_runtime?.SaveAll();
		}

		private void OnDestroy()
		{
			MinimapManager.OnVanillaMapAvailable -= HandleMapAvailable;
			MinimapManager.OnVanillaMapDataLoaded -= HandleMapDataLoaded;
			_runtime?.Dispose();
			_runtime = null;
			_crashHub?.Dispose();
			_crashHub = null;
		}
	}
}
namespace TheConcernedCat.ConcernedCartographer.Runtime
{
	internal sealed class AtlasToolsCommand : ConsoleCommand
	{
		private readonly CartographerRuntime _runtime;

		public override string Name => "cc_atlas";

		public override string Help => "Concerned Cartographer atlas drawer and maintenance. Subcommands: status, query <text>, clear, pins on|off, cluster on|off, dirt on|off, paved on|off, view save|apply|del <name>, views, compat, backup, backups, restore <n>, support. Drawer panel: DrawerHotkey (default L) on the large map.";

		public AtlasToolsCommand(CartographerRuntime runtime)
		{
			_runtime = runtime;
		}

		public override void Run(string[] args, Terminal context)
		{
			string text;
			try
			{
				text = _runtime.ExecuteAtlasCommand(args);
			}
			catch (Exception ex)
			{
				text = "Atlas tool failed: " + ex.Message;
			}
			if (context != null)
			{
				context.AddString(text);
			}
		}

		public override List<string> CommandOptionList()
		{
			return new List<string>
			{
				"status", "query", "clear", "pins", "cluster", "dirt", "paved", "view", "views", "compat",
				"backup", "backups", "restore", "support"
			};
		}
	}
	internal sealed class CartographerRuntime : IDisposable
	{
		private readonly CartographerSettings _settings;

		private readonly ManualLogSource _log;

		private readonly RoadPersistence _persistence;

		private readonly PinPersistence _pinPersistence;

		private readonly GroundPaintProbe _probe;

		private readonly RoadOverlayRenderer _renderer;

		private readonly ConstructionCapture _constructionCapture;

		private readonly PinAdapter _pinAdapter;

		private readonly RateLimitedLog _rateLimited;

		private readonly ModalInputBlock _textFocusBlock = new ModalInputBlock((Action<bool>)GUIManager.BlockInput);

		private const float RedrawDebounceSeconds = 0.5f;

		private bool _redrawPending;

		private float _redrawElapsed;

		private RoadAtlas _atlas = new RoadAtlas();

		private TerrainIntentMask _terrainIntent = new TerrainIntentMask();

		private readonly TerrainIntentPersistence _terrainIntentPersistence;

		private RoadObservationPipeline? _pipeline;

		private RoadAtlasEditor? _editor;

		private RoadSurveyor? _surveyor;

		private PinStore _pinStore = new PinStore();

		private PinCommandHandler? _pinCommands;

		private readonly PinWorkbenchPanel _workbenchPanel;

		private readonly PinDisplayController _displayController;

		private readonly AtlasDrawerPanel _drawerPanel;

		private readonly SavedViewPersistence _savedViewPersistence;

		private SavedViewStore _savedViews = new SavedViewStore();

		private readonly MapUiCoordinator _mapUi;

		private readonly CrashConsentPanel _consentPanel;

		private bool _consentPromptChecked;

		private readonly PinPalettePanel _palettePanel;

		private readonly RoutesPanel _routesPanel;

		private readonly SurveyPanel _surveyPanel;

		private readonly SharePanel _sharePanel;

		private readonly SettingsPanel _settingsPanel;

		private readonly SystemMarkersPanel _systemMarkersPanel;

		private int _drawerToken;

		private int _paletteToken;

		private int _routesToken;

		private int _surveyToken;

		private int _shareToken;

		private int _settingsToken;

		private int _systemMarkersToken;

		private int _workbenchToken;

		private readonly QuickPinInputGate _quickPinGate = new QuickPinInputGate();

		private readonly PaletteBirthTracker<PinData> _birthTracker = new PaletteBirthTracker<PinData>();

		private float _hintElapsed;

		private readonly OrphanChromeSweep _chromeSweep = new OrphanChromeSweep();

		private string _lastChromeSweepDiagnostics = "";

		private readonly DefaultPanelRule _defaultPanel = new DefaultPanelRule();

		private const float ContextGraceSeconds = 1.5f;

		private float _contextGrace;

		private readonly QuickPinCapture _quickPinCapture;

		private readonly SurveyEngine _surveyEngine = new SurveyEngine();

		private readonly SurveyScanner _surveyScanner;

		private readonly SurveyRulePersistence _surveyRulePersistence;

		private readonly SurveyRejectedPersistence _surveyRejectedPersistence;

		private readonly RoutePersistence _routePersistence;

		private readonly RouteOverlayRenderer _routeRenderer;

		private readonly OverlayPanelRelabel _overlayRelabel;

		private float _relabelElapsed;

		private RouteStore _routeStore = new RouteStore();

		private RouteCommandHandler? _routeCommands;

		private bool _routeRedrawPending;

		private float _routeRedrawElapsed;

		private readonly SyncInbox _syncInbox = new SyncInbox();

		private readonly SyncTransport _syncTransport;

		private string _authorId = "";

		private readonly CompatibilityRegistry _compatibility = new CompatibilityRegistry();

		private readonly AtlasBackupTools _backupTools;

		private long? _worldUid;

		private bool _mapReady;

		private float _autosaveElapsed;

		private bool _disposed;

		private readonly MapSessionTracker _mapSession = new MapSessionTracker();

		private string _lastRailDiagnostics = "";

		private bool _onboardingChecked;

		private string _lastToolSummary = "";

		internal PinStore Pins => _pinStore;

		internal PinAdapter PinAdapter => _pinAdapter;

		internal PinCommandHandler? PinCommands => _pinCommands;

		public CartographerRuntime(CartographerSettings settings, ManualLogSource log)
		{
			_settings = settings;
			_log = log;
			_persistence = new RoadPersistence(log);
			_terrainIntentPersistence = new TerrainIntentPersistence(log);
			_pinPersistence = new PinPersistence(log);
			_probe = new GroundPaintProbe(settings, log);
			_renderer = new RoadOverlayRenderer(settings, log);
			_rateLimited = new RateLimitedLog(log, 5f);
			_pinAdapter = new PinAdapter(log);
			_workbenchPanel = new PinWorkbenchPanel(log);
			_displayController = new PinDisplayController(log);
			_savedViewPersistence = new SavedViewPersistence(log);
			_savedViews = _savedViewPersistence.Load();
			_drawerPanel = new AtlasDrawerPanel(log);
			WireDrawer();
			_mapUi = new MapUiCoordinator(log);
			_consentPanel = new CrashConsentPanel(log, settings);
			_palettePanel = new PinPalettePanel(log);
			_routesPanel = new RoutesPanel(log, () => _routeCommands);
			_surveyPanel = new SurveyPanel(log, settings, ExecuteSurveyCommand, () => _surveyEngine.Observations, () => _surveyEngine, () => _surveyScanner);
			_sharePanel = new SharePanel(log, ExecuteSyncCommand, delegate
			{
				List<string> list = new List<string>();
				foreach (SyncInbox.Envelope envelope in _syncInbox.Envelopes)
				{
					list.Add(envelope.AuthorName);
				}
				return list;
			});
			_settingsPanel = new SettingsPanel(log, ExecuteAtlasCommand, ExecuteRoadCommand, delegate
			{
				_consentPanel.ShowSettings();
			});
			_systemMarkersPanel = new SystemMarkersPanel(log);
			_drawerToken = _mapUi.RegisterSurface(() => _drawerPanel.IsVisible, _drawerPanel.Hide);
			_paletteToken = _mapUi.RegisterSurface(() => _palettePanel.IsVisible, _palettePanel.Hide);
			_routesToken = _mapUi.RegisterSurface(() => _routesPanel.IsVisible, _routesPanel.Hide);
			_surveyToken = _mapUi.RegisterSurface(() => _surveyPanel.IsVisible, _surveyPanel.Hide);
			_shareToken = _mapUi.RegisterSurface(() => _sharePanel.IsVisible, _sharePanel.Hide);
			_settingsToken = _mapUi.RegisterSurface(() => _settingsPanel.IsVisible, _settingsPanel.Hide);
			_systemMarkersToken = _mapUi.RegisterSurface(() => _systemMarkersPanel.IsVisible, _systemMarkersPanel.Hide);
			_workbenchToken = _mapUi.RegisterSurface(() => _workbenchPanel.IsVisible, _workbenchPanel.Close);
			_mapUi.AtlasClicked = delegate
			{
				_mapUi.OpenExclusive(_drawerToken, ToggleDrawer);
			};
			_mapUi.MarkersClicked = delegate
			{
				if (PaletteActive())
				{
					_palettePanel.UiScale = _settings.UiScale.Value;
					_palettePanel.EnsureBuilt();
					_mapUi.OpenExclusive(_paletteToken, _palettePanel.Toggle);
				}
				else
				{
					Player localPlayer = Player.m_localPlayer;
					if (localPlayer != null)
					{
						((Character)localPlayer).Message((MessageType)1, "The enhanced marker palette is disabled (setting or a conflicting pin manager); the vanilla selector is shown instead.", 0, (Sprite)null);
					}
				}
			};
			_mapUi.RoutesClicked = delegate
			{
				OpenSidePanel(_routesToken, _routesPanel);
			};
			_mapUi.SurveyClicked = delegate
			{
				OpenSidePanel(_surveyToken, _surveyPanel);
			};
			_mapUi.ShareClicked = delegate
			{
				OpenSidePanel(_shareToken, _sharePanel);
			};
			_mapUi.SettingsClicked = delegate
			{
				OpenSidePanel(_settingsToken, _settingsPanel);
			};
			_mapUi.QuickPinClicked = ArmQuickPin;
			_drawerPanel.PrivacyClicked = delegate
			{
				_consentPanel.ShowSettings();
			};
			_drawerPanel.SystemMarkersClicked = delegate
			{
				OpenSidePanel(_systemMarkersToken, _systemMarkersPanel);
			};
			MapInputGate.Install(log);
			PlayerInputGate.Install(log);
			PlayerInputGate.SuppressAttack = () => _quickPinGate.SuppressAttack(Time.frameCount);
			PlayerInputGate.SuppressMenu = () => _quickPinGate.SuppressMenu(Time.frameCount);
			PinDeletionWatch.Install(log);
			PinDeletionWatch.ExplicitDelete = HandleExplicitVanillaDelete;
			MapInputGate.WheelGuard = () => Minimap.IsOpen() && (MapPointerGuard.IsPointerOverCcUi(Vector2.op_Implicit(Input.mousePosition)) || CcTextFocus.AnyFieldFocused());
			MapPointerGuard.Clear();
			MapPointerGuard.RegisterWidget(() => _mapUi.ToolbarObject);
			MapPointerGuard.RegisterWidget(() => _mapUi.ContextButtonObject);
			MapPointerGuard.RegisterWidget(() => _palettePanel.PanelObject);
			_palettePanel.IconChosen = delegate(IconRegistry.IconDefinition definition)
			{
				MinimapReflection.TrySelectIcon(definition.VanillaType);
				_birthTracker.Arm(definition.Id, definition.DefaultCategory);
			};
			_palettePanel.SelectionCleared = delegate
			{
				_birthTracker.Disarm();
			};
			_quickPinCapture = new QuickPinCapture(settings, log);
			_surveyRulePersistence = new SurveyRulePersistence(log);
			_surveyRejectedPersistence = new SurveyRejectedPersistence(log);
			_surveyEngine.Rules = _surveyRulePersistence.LoadOrCreate();
			_surveyScanner = new SurveyScanner(settings, log);
			_routePersistence = new RoutePersistence(log);
			_routeRenderer = new RouteOverlayRenderer(settings, log);
			_overlayRelabel = new OverlayPanelRelabel(log);
			_renderer.UserToggledOverlay += delegate(RoadKind kind, bool enabled)
			{
				if (kind == RoadKind.Dirt)
				{
					_settings.DrawerShowDirt.Value = enabled;
				}
				else
				{
					_settings.DrawerShowPaved.Value = enabled;
				}
			};
			_routeRenderer.UserToggled += delegate(bool enabled)
			{
				_renderer.SetRouteVectorVisible(enabled);
			};
			_authorId = AuthorIdentity.Get(log);
			_syncTransport = new SyncTransport(log, _syncInbox)
			{
				LocalAuthorId = _authorId
			};
			_backupTools = new AtlasBackupTools(log);
			_constructionCapture = new ConstructionCapture(log);
			_constructionCapture.OperationCaptured += HandleTerrainOperation;
		}

		public void OnMapAvailable()
		{
			if (_disposed)
			{
				return;
			}
			if (!WorldContext.TryGetWorldUid(out var uid))
			{
				_log.LogWarning((object)"Map became available before a world UID could be resolved; waiting for the next map event.");
				_mapReady = false;
				return;
			}
			SwitchWorld(uid);
			_mapReady = true;
			_log.LogInfo((object)string.Format("Map session lifecycle: generation {0} (map-available).", _mapSession.NoteTransition("map-available")));
			_renderer.ResetMapSession();
			_routeRenderer.ResetMapSession();
			CcIconSprites.ResetSession();
			_renderer.RedrawAll(_atlas);
			_pinAdapter.ReconcileOnMapReady(_pinStore);
			_mapSession.NoteBound();
			_renderer.SetOverlayEnabled(RoadKind.Dirt, _settings.DrawerShowDirt.Value);
			_renderer.SetOverlayEnabled(RoadKind.Paved, _settings.DrawerShowPaved.Value);
			_displayController.ShowPins = _settings.DrawerShowPins.Value;
			_displayController.ClusterEnabled = _settings.DrawerCluster.Value;
			_displayController.Apply(_pinStore, _pinAdapter);
			_routeRenderer.RedrawAll(_routeStore);
			_renderer.MarkVectorDataDirty();
			_syncTransport.EnsureRegistered();
			_compatibility.Evaluate(_log);
			ShowOnboardingOnce();
			if (_settings.DrawCalibrationMarkers.Value)
			{
				_renderer.DrawCalibrationMarkers();
			}
			_log.LogInfo((object)$"Road atlas ready: {_atlas.Strokes.Count} stroke(s), {_atlas.PointCount} point(s).");
		}

		public void OnMapDataReconstructed()
		{
			if (!_disposed)
			{
				if (!_mapReady)
				{
					OnMapAvailable();
					return;
				}
				_log.LogInfo((object)string.Format("Map session lifecycle: generation {0} (map-data-loaded).", _mapSession.NoteTransition("map-data-loaded")));
				_pinAdapter.ReconcileOnMapReady(_pinStore, "map-data-loaded");
				_mapSession.NoteBound();
				ReapplyDisplay();
			}
		}

		private void HandleExplicitVanillaDelete(PinData pin)
		{
			if (!_disposed && _mapReady)
			{
				_pinAdapter.HandleExplicitVanillaDelete(_pinStore, pin);
			}
		}

		public void Tick(float unscaledDeltaTime)
		{
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_0497: Unknown result type (might be due to invalid IL or missing references)
			//IL_048b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ca: Unknown result type (might be due to invalid IL or missing references)
			if (_disposed)
			{
				return;
			}
			_workbenchPanel.HandleFrame();
			_consentPanel.HandleFrame();
			_routesPanel.HandleFrame();
			_surveyPanel.HandleFrame();
			_sharePanel.HandleFrame();
			_settingsPanel.HandleFrame();
			_systemMarkersPanel.HandleFrame();
			_palettePanel.HandleFrame();
			if (!Minimap.IsOpen())
			{
				MapInputGate.ConsumeClicks = false;
			}
			if (!_settings.Enabled.Value || !_mapReady || _surveyor == null)
			{
				MapInputGate.ConsumeClicks = false;
				_textFocusBlock.Release();
				_quickPinGate.Disarm();
				if (!_settings.Enabled.Value)
				{
					_renderer.EnsureTextureFallback();
					_routeRenderer.TickVisibility(vectorRoutesActive: false);
					_overlayRelabel.Restore();
				}
				if (Minimap.IsOpen())
				{
					EnforceVanillaPaletteVisibility();
					_palettePanel.SetUnavailable();
				}
				if (_mapUi.AnySurfaceVisible)
				{
					_mapUi.CloseAllSurfaces();
				}
				return;
			}
			_drawerPanel.HandleFrame();
			bool flag = CcTextFocus.AnyFieldFocused();
			if (flag)
			{
				_textFocusBlock.Acquire();
			}
			else
			{
				_textFocusBlock.Release();
			}
			if (!Minimap.IsOpen() && !Minimap.InTextInput() && !flag)
			{
				if (_quickPinGate.Armed)
				{
					switch (_quickPinGate.HandleFrame(Time.frameCount, Input.GetKeyDown((KeyCode)27), Input.GetMouseButtonDown(0) || ((int)_settings.QuickPinHotkey.Value != 0 && Input.GetKeyDown(_settings.QuickPinHotkey.Value)) || GamepadDown(_settings.WorkbenchGamepadButton.Value)))
					{
					case QuickPinInputGate.FrameAction.Cancel:
					{
						Player localPlayer = Player.m_localPlayer;
						if (localPlayer != null)
						{
							((Character)localPlayer).Message((MessageType)1, AtlasStrings.Get("quickpin.cancelled"), 0, (Sprite)null);
						}
						break;
					}
					case QuickPinInputGate.FrameAction.Capture:
						CaptureQuickPin();
						break;
					}
				}
				else if ((int)_settings.QuickPinHotkey.Value != 0 && Input.GetKeyDown(_settings.QuickPinHotkey.Value))
				{
					CaptureQuickPin();
				}
			}
			if (!Minimap.IsOpen())
			{
				_defaultPanel.NoteMapClosed();
			}
			if (Minimap.IsOpen() && !Minimap.InTextInput() && !flag)
			{
				_mapUi.EnsureBuilt(((object)_settings.DrawerHotkey.Value/*cast due to .constrained prefix*/).ToString());
				if (!_consentPromptChecked)
				{
					_consentPromptChecked = true;
					if (_consentPanel.NeedsFirstRunPrompt)
					{
						_consentPanel.ShowFirstRun();
					}
				}
				if (PaletteActive())
				{
					_palettePanel.UiScale = _settings.UiScale.Value;
					_palettePanel.EnsureBuilt();
				}
				else
				{
					_palettePanel.SetUnavailable();
				}
				if (_defaultPanel.IsArmed && _defaultPanel.ShouldAutoOpen(PaletteActive() && !_mapUi.HasFailed && AtlasAccessAllowed(out string _), _mapUi.AnySurfaceVisible))
				{
					_palettePanel.UiScale = _settings.UiScale.Value;
					_palettePanel.EnsureBuilt();
					_mapUi.OpenExclusive(_paletteToken, delegate
					{
						if (!_palettePanel.IsVisible)
						{
							_palettePanel.Toggle();
						}
					});
				}
				UpdateEditHint(unscaledDeltaTime);
				if (_pinCommands != null && !_workbenchPanel.IsVisible && (Input.GetKeyDown(_settings.WorkbenchHotkey.Value) || GamepadDown(_settings.WorkbenchGamepadButton.Value)))
				{
					OpenWorkbenchAtCursor();
				}
				if (Input.GetKeyDown(_settings.DrawerHotkey.Value) || GamepadDown(_settings.DrawerGamepadButton.Value))
				{
					_mapUi.OpenExclusive(_drawerToken, ToggleDrawer);
				}
				if (_displayController.ZoomTierChanged())
				{
					_displayController.Apply(_pinStore, _pinAdapter);
				}
				bool flag2 = (MapInputGate.ConsumeClicks = _routeCommands != null && _routeCommands.Mode != RouteCommandHandler.MapMode.None && _routeCommands.UiModeOwned);
				if (flag2)
				{
					MinimapReflection.TrySuppressMapDragThisFrame();
				}
				if (_routeCommands != null && _routeCommands.Mode != RouteCommandHandler.MapMode.None && (flag2 || Input.GetKey(_settings.RouteDrawModifier.Value)) && MinimapReflection.TryScreenToWorldPoint(Input.mousePosition, out var worldPosition))
				{
					bool flag3 = MapPointerGuard.IsPointerOverCcUi(Vector2.op_Implicit(Input.mousePosition));
					_routeCommands.HandleMapFrame(new RoadPoint(worldPosition.x, worldPosition.y, worldPosition.z), Input.GetMouseButton(0) && !flag3, Input.GetMouseButtonDown(0) && !flag3);
				}
			}
			_routeRedrawElapsed += unscaledDeltaTime;
			if (_routeRedrawPending && _routeRedrawElapsed >= 0.5f)
			{
				_routeRedrawElapsed = 0f;
				_routeRedrawPending = false;
				_routeRenderer.RedrawAll(_routeStore);
				_renderer.MarkVectorDataDirty();
			}
			if (!WorldContext.TryGetWorldUid(out var uid) || _worldUid != uid)
			{
				_mapReady = false;
				_log.LogInfo((object)string.Format("Map session lifecycle: generation {0} (world-unloaded).", _mapSession.NoteTransition("world-unloaded")));
				_workbenchPanel.Close();
				_mapUi.CloseAllSurfaces();
				_drawerPanel.FlushPosition();
				MapInputGate.ConsumeClicks = false;
				_textFocusBlock.Release();
				_quickPinGate.Disarm();
				_pipeline?.EndAllStrokes();
				_displayController.Reset();
				_mapUi.Reset();
				_palettePanel.Reset();
				_chromeSweep.RestoreAll();
				_birthTracker.Reset();
				_pinAdapter.Reset();
				SaveIfDirty();
				SavePinsSnapshot();
				return;
			}
			_surveyor.Tick(unscaledDeltaTime);
			_renderer.TickVectorLayer(unscaledDeltaTime, _atlas, _routeStore);
			_routeRenderer.TickVisibility(_renderer.VectorLayerActive);
			_relabelElapsed += unscaledDeltaTime;
			if (_relabelElapsed >= 1f)
			{
				_relabelElapsed = 0f;
				if (Minimap.IsOpen())
				{
					_overlayRelabel.EnsureApplied();
				}
			}
			_surveyScanner.Tick(unscaledDeltaTime, _surveyEngine, _pinStore);
			if (_settings.EnhancedPinPalette.Value && MinimapReflection.TryGetNamePin(out PinData namePin))
			{
				PinData val = _birthTracker.Observe(namePin);
				if (val != null)
				{
					HandlePaletteBirth(val);
				}
				if (namePin != null && _birthTracker.IsArmed)
				{
					_pinAdapter.ApplyImmediateSprite(namePin, _birthTracker.IconId);
				}
			}
			_redrawElapsed += unscaledDeltaTime;
			if (_redrawPending && _redrawElapsed >= 0.5f)
			{
				_redrawPending = false;
				_redrawElapsed = 0f;
				_renderer.RedrawAll(_atlas);
			}
			_autosaveElapsed += unscaledDeltaTime;
			if (_autosaveElapsed >= _settings.AutosaveIntervalSeconds.Value)
			{
				_autosaveElapsed = 0f;
				SaveIfDirty();
				_pinAdapter.AbsorbVanillaChanges(_pinStore);
				if (_pinAdapter.NeedsRebind && _pinAdapter.IsOperational)
				{
					_pinAdapter.ReconcileOnMapReady(_pinStore, "rendering-loss-repair");
					_mapSession.NoteBound();
					ReapplyDisplay();
				}
				_pinPersistence.FlushJournal();
				_routePersistence.FlushJournal();
				SaveRejectedIfDirty();
			}
		}

		internal string ExecutePinCommand(string[] args)
		{
			//IL_0071: 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)
			if (!AtlasAccessAllowed(out string denial))
			{
				return denial;
			}
			if (_disposed || !_mapReady || _pinCommands == null)
			{
				return "Concerned Cartographer: no world is loaded yet.";
			}
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer == null)
			{
				return "Concerned Cartographer: no local player.";
			}
			if (args.Length != 0 && string.Equals(args[0], "edit", StringComparison.OrdinalIgnoreCase))
			{
				OpenWorkbenchNear(((Component)localPlayer).transform.position);
				return "Opening the Pin Workbench for the nearest pin.";
			}
			return _pinCommands.Execute(args, ((Component)localPlayer).transform.position);
		}

		private void WireDrawer()
		{
			_drawerPanel.LoadPosition = () => _settings.DrawerPanelPosition.Value;
			_drawerPanel.PositionCaptured = delegate(string stored)
			{
				_settings.DrawerPanelPosition.Value = stored;
			};
			_drawerPanel.DirtToggled = delegate(bool value)
			{
				_settings.DrawerShowDirt.Value = value;
				_renderer.SetOverlayEnabled(RoadKind.Dirt, value);
			};
			_drawerPanel.PavedToggled = delegate(bool value)
			{
				_settings.DrawerShowPaved.Value = value;
				_renderer.SetOverlayEnabled(RoadKind.Paved, value);
			};
			_drawerPanel.PinsToggled = delegate(bool value)
			{
				_settings.DrawerShowPins.Value = value;
				_displayController.ShowPins = value;
				ReapplyDisplay();
			};
			_drawerPanel.ClusterToggled = delegate(bool value)
			{
				_settings.DrawerCluster.Value = value;
				_displayController.ClusterEnabled = value;
				ReapplyDisplay();
			};
			_drawerPanel.QueryApplied = delegate(string query)
			{
				_displayController.SetQuery(query);
				ReapplyDisplay();
			};
			_drawerPanel.ViewSaved = delegate(string name)
			{
				_savedViews.Save(new SavedView(name, _displayController.QueryText, _settings.DrawerShowDirt.Value, _settings.DrawerShowPaved.Value, _displayController.ShowPins, _displayController.ClusterEnabled));
				_savedViewPersistence.Save(_savedViews);
			};
			_drawerPanel.ViewApplied = delegate(string name)
			{
				ApplySavedView(name);
			};
			_drawerPanel.ResultClicked = OpenWorkbenchForId;
			_drawerPanel.StatusLine = () => $"{_displayController.VisibleCount} shown · {_displayController.HiddenByFilter} hidden · {_displayController.ClusterCount} grouped";
			_drawerPanel.TopResults = delegate
			{
				List<(string, AtlasId)> list = new List<(string, AtlasId)>();
				PinQuery pinQuery = PinQuery.Parse(_displayController.QueryText);
				foreach (AtlasPin item in _pinStore.Living)
				{
					if (!item.Archived && pinQuery.Matches(item))
					{
						list.Add(((item.Name.Length == 0) ? "(unnamed)" : item.Name, item.Id));
						if (list.Count >= 6)
						{
							break;
						}
					}
				}
				return list;
			};
			_drawerPanel.ViewNames = delegate
			{
				List<string> list = new List<string>();
				foreach (SavedView view in _savedViews.Views)
				{
					list.Add(view.Name);
					if (list.Count >= 5)
					{
						break;
					}
				}
				return list;
			};
		}

		private bool ApplySavedView(string name)
		{
			if (!_savedViews.TryGet(name, out SavedView view))
			{
				return false;
			}
			_settings.DrawerShowDirt.Value = view.ShowDirt;
			_settings.DrawerShowPaved.Value = view.ShowPaved;
			_settings.DrawerShowPins.Value = view.ShowPins;
			_settings.DrawerCluster.Value = view.ClusterEnabled;
			_renderer.SetOverlayEnabled(RoadKind.Dirt, view.ShowDirt);
			_renderer.SetOverlayEnabled(RoadKind.Paved, view.ShowPaved);
			_displayController.ShowPins = view.ShowPins;
			_displayController.ClusterEnabled = view.ClusterEnabled;
			_displayController.SetQuery(view.Query);
			ReapplyDisplay();
			return true;
		}

		private void ReapplyDisplay()
		{
			if (_mapReady)
			{
				_displayController.Apply(_pinStore, _pinAdapter);
			}
		}

		private void ResyncPins()
		{
			_pinAdapter.SyncAllPins(_pinStore, _displayController.IsDisplayHidden);
			ReapplyDisplay();
		}

		private void CaptureQuickPin()
		{
			if (_quickPinCapture.TryCapture(_pinStore, out string message, out AtlasPin created))
			{
				if (created != null)
				{
					_displayController.MarkStickyVisible(created.Id);
				}
				ResyncPins();
			}
			if (message.Length > 0)
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)1, message, 0, (Sprite)null);
				}
			}
		}

		private bool PaletteActive()
		{
			if (_settings.EnhancedPinPalette.Value && !_compatibility.PinManagerPresent)
			{
				return !_palettePanel.HasFailed;
			}
			return false;
		}

		private void OpenSidePanel(int token, CcSidePanel panel)
		{
			if (!AtlasAccessAllowed(out string denial))
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)1, denial, 0, (Sprite)null);
				}
			}
			else
			{
				panel.UiScale = _settings.UiScale.Value;
				_mapUi.OpenExclusive(token, panel.Toggle);
			}
		}

		private void ArmQuickPin()
		{
			if (!AtlasAccessAllowed(out string denial))
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)1, denial, 0, (Sprite)null);
				}
				return;
			}
			try
			{
				_mapUi.CloseAllSurfaces();
				Minimap instance = Minimap.instance;
				if (instance != null)
				{
					instance.SetMapMode((MapMode)1);
				}
			}
			catch
			{
			}
			_quickPinGate.Arm(Time.frameCount);
			Player localPlayer2 = Player.m_localPlayer;
			if (localPlayer2 != null)
			{
				((Character)localPlayer2).Message((MessageType)2, AtlasStrings.Get("quickpin.armed"), 0, (Sprite)null);
			}
		}

		private void ToggleDrawer()
		{
			if (AtlasAccessAllowed(out string denial))
			{
				_drawerPanel.UiScale = _settings.UiScale.Value;
				_drawerPanel.Toggle(_settings.DrawerShowDirt.Value, _settings.DrawerShowPaved.Value, _settings.DrawerShowPins.Value, _settings.DrawerCluster.Value);
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)1, denial, 0, (Sprite)null);
			}
		}

		private void UpdateEditHint(float unscaledDeltaTime)
		{
			//IL_0061: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			_hintElapsed += unscaledDeltaTime;
			if (_hintElapsed < 0.2f)
			{
				return;
			}
			_hintElapsed = 0f;
			EnforceVanillaPaletteVisibility();
			_mapUi.UpdateLayout();
			if (_workbenchPanel.IsVisible)
			{
				_mapUi.SetHint(null);
				_mapUi.SetContext(null, null);
				return;
			}
			PinData pin = null;
			Vector3 worldPosition;
			float distance;
			bool flag = MinimapReflection.TryScreenToWorldPoint(Input.mousePosition, out worldPosition) && _pinAdapter.TryFindNearest(worldPosition, 30f, out pin, out distance);
			if (flag && _pinAdapter.TryGetManagedId(pin, out var id))
			{
				_contextGrace = 1.5f;
				_mapUi.SetHint(AtlasStrings.Format("hud.editHint", _settings.WorkbenchHotkey.Value));
				AtlasId captured = id;
				_mapUi.SetContext(AtlasStrings.Get("hud.editPin"), delegate
				{
					OpenWorkbenchForId(captured);
				});
			}
			else if (flag && _pinAdapter.IsAdoptableVanilla(pin) && !_compatibility.PinManagerPresent)
			{
				_contextGrace = 1.5f;
				_mapUi.SetHint(AtlasStrings.Format("hud.editHint", _settings.WorkbenchHotkey.Value));
				PinData capturedPin = pin;
				_mapUi.SetContext(AtlasStrings.Get("hud.upgradeEdit"), delegate
				{
					UpgradeAndEdit(capturedPin);
				});
			}
			else if (!_mapUi.PointerOverContext)
			{
				_contextGrace -= 0.2f;
				if (!(_contextGrace > 0f))
				{
					_mapUi.SetHint(null);
					_mapUi.SetContext(null, null);
				}
			}
		}

		private void OpenWorkbenchForId(AtlasId id)
		{
			if (_pinCommands == null || !_pinStore.TryGet(id, out AtlasPin pin) || pin.Deleted)
			{
				return;
			}
			if (!AtlasAccessAllowed(out string denial))
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)1, denial, 0, (Sprite)null);
				}
			}
			else
			{
				_workbenchPanel.UiScale = _settings.UiScale.Value;
				_mapUi.OpenExclusive(_workbenchToken, delegate
				{
					_workbenchPanel.OpenForManaged(pin, _pinCommands.Operations, ResyncPins);
				});
			}
		}

		private void UpgradeAndEdit(PinData pin)
		{
			if (_pinCommands == null)
			{
				return;
			}
			if (!AtlasAccessAllowed(out string denial))
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)1, denial, 0, (Sprite)null);
				}
			}
			else
			{
				if (!_pinAdapter.ContainsPin(pin) || !_pinAdapter.IsAdoptableVanilla(pin))
				{
					return;
				}
				AtlasPin managed = _pinAdapter.Adopt(_pinStore, pin);
				if (managed != null)
				{
					_workbenchPanel.UiScale = _settings.UiScale.Value;
					_mapUi.OpenExclusive(_workbenchToken, delegate
					{
						_workbenchPanel.OpenForManaged(managed, _pinCommands.Operations, ResyncPins);
					});
				}
			}
		}

		private void HandlePaletteBirth(PinData born)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Expected I4, but got Unknown
			string committedName = born.m_name ?? "";
			bool num = _pinAdapter.ContainsPin(born);
			PinData val = (num ? null : _pinAdapter.TryFindAdoptableAt(born.m_pos, committedName));
			PaletteBirthResolution.Action action = PaletteBirthResolution.Decide(num, num && _pinAdapter.IsAdoptableVanilla(born), val != null, committedName);
			AtlasPin atlasPin;
			switch (action)
			{
			case PaletteBirthResolution.Action.AdoptBorn:
				atlasPin = _pinAdapter.Adopt(_pinStore, born);
				break;
			case PaletteBirthResolution.Action.AdoptReplacement:
				atlasPin = _pinAdapter.Adopt(_pinStore, val);
				_log.LogInfo((object)"Palette birth: the naming close replaced the pin object; adopted the replacement at the same spot (RC12 blocker 5).");
				break;
			case PaletteBirthResolution.Action.RecreateManaged:
			{
				RoadPoint position = new RoadPoint(born.m_pos.x, born.m_pos.y, born.m_pos.z);
				int bornType = (int)born.m_type;
				atlasPin = _pinStore.Create(delegate(AtlasPin pin)
				{
					pin.Name = committedName;
					pin.IconId = IconRegistry.FromVanillaType(bornType);
					pin.Source = AtlasPinSource.Managed;
					pin.Position = position;
				});
				_log.LogInfo((object)"Palette birth: the named pin's rendering vanished at naming close; recreated it as a managed marker (RC12 blocker 5).");
				break;
			}
			case PaletteBirthResolution.Action.DropForeign:
				_log.LogInfo((object)"Palette birth: the named pin is not adoptable (foreign or already tracked); left untouched.");
				return;
			default:
				if (_settings.DebugLogging.Value)
				{
					_log.LogInfo((object)"Palette birth: naming was cancelled; nothing created.");
				}
				return;
			}
			if (atlasPin == null)
			{
				return;
			}
			string iconId = _birthTracker.IconId;
			string category = _birthTracker.Category;
			_pinStore.Mutate(atlasPin.Id, delegate(AtlasPin pin)
			{
				if (iconId.Length > 0)
				{
					pin.IconId = iconId;
				}
				pin.Category = category;
				pin.Source = AtlasPinSource.Managed;
			});
			_palettePanel.NoteUsed(iconId);
			_displayController.MarkStickyVisible(atlasPin.Id);
			ResyncPins();
			if (_settings.DebugLogging.Value)
			{
				_log.LogInfo((object)$"Palette marker born managed: {atlasPin.Id} icon {iconId} category \"{category}\".");
			}
		}

		private void EnforceVanillaPaletteVisibility()
		{
			bool flag = !_settings.Enabled.Value || !_settings.EnhancedPinPalette.Value || _settings.ShowVanillaPinPalette.Value || _settings.ShowVanillaMapControls.Value || _compatibility.PinManagerPresent || _palettePanel.HasFailed || _mapUi.HasFailed;
			foreach (GameObject placeableIconButton in MinimapReflection.GetPlaceableIconButtons())
			{
				if ((Object)(object)placeableIconButton != (Object)null && placeableIconButton.activeSelf != flag)
				{
					placeableIconButton.SetActive(flag);
				}
			}
			bool flag2 = !_settings.Enabled.Value || _settings.ShowVanillaMapControls.Value || _compatibility.PinManagerPresent || _systemMarkersPanel.HasFailed || _drawerPanel.HasFailed || _mapUi.HasFailed;
			foreach (GameObject systemFilterButton in MinimapReflection.GetSystemFilterButtons())
			{
				if ((Object)(object)systemFilterButton != (Object)null && systemFilterButton.activeSelf != flag2)
				{
					systemFilterButton.SetActive(flag2);
				}
			}
			GameObject val = null;
			try
			{
				val = (((Object)(object)Minimap.instance != (Object)null && (Object)(object)Minimap.instance.m_publicPosition != (Object)null) ? ((Component)Minimap.instance.m_publicPosition).gameObject : null);
				if ((Object)(object)val != (Object)null && val.activeSelf != flag2)
				{
					val.SetActive(flag2);
				}
			}
			catch
			{
			}
			if (MinimapReflection.TryGetVanillaRailContainers(out GameObject placeablesContainer, out GameObject filtersContainer, out bool sharedContainer, out string diagnostics))
			{
				if (sharedContainer)
				{
					SetRailContainerActive(placeablesContainer, flag || flag2);
				}
				else
				{
					if ((Object)(object)placeablesContainer != (Object)null)
					{
						SetRailContainerActive(placeablesContainer, flag);
					}
					if ((Object)(object)filtersContainer != (Object)null)
					{
						SetRailContainerActive(filtersContainer, flag2);
					}
				}
			}
			if (!string.Equals(diagnostics, _lastRailDiagnostics, StringComparison.Ordinal))
			{
				_lastRailDiagnostics = diagnostics;
				_log.LogInfo((object)("Vanilla rail chrome: " + diagnostics + "."));
			}
			if (OrphanChromeRule.MustRestore(flag || flag2))
			{
				_chromeSweep.RestoreAll();
			}
			else
			{
				List<GameObject> list = new List<GameObject> { placeablesContainer, filtersContainer, val };
				foreach (GameObject placeableIconButton2 in MinimapReflection.GetPlaceableIconButtons())
				{
					list.Add(placeableIconButton2);
				}
				foreach (GameObject systemFilterButton2 in MinimapReflection.GetSystemFilterButtons())
				{
					list.Add(systemFilterButton2);
				}
				_chromeSweep.Sweep(list);
			}
			if (!string.Equals(_chromeSweep.LastDiagnostics, _lastChromeSweepDiagnostics, StringComparison.Ordinal))
			{
				_lastChromeSweepDiagnostics = _chromeSweep.LastDiagnostics;
				if (_lastChromeSweepDiagnostics.Length > 0)
				{
					_log.LogInfo((object)("Vanilla chrome sweep: " + _lastChromeSweepDiagnostics + "."));
				}
			}
		}

		private static void SetRailContainerActive(GameObject container, bool visible)
		{
			if (container.activeSelf != visible)
			{
				container.SetActive(visible);
			}
		}

		private void RestoreVanillaPalette()
		{
			try
			{
				_chromeSweep.RestoreAll();
				if (MinimapReflection.TryGetVanillaRailContainers(out GameObject placeablesContainer, out GameObject filtersContainer, out bool _, out string _))
				{
					if ((Object)(object)placeablesContainer != (Object)null && !placeablesContainer.activeSelf)
					{
						placeablesContainer.SetActive(true);
					}
					if ((Object)(object)filtersContainer != (Object)null && !filtersContainer.activeSelf)
					{
						filtersContainer.SetActive(true);
					}
				}
				foreach (GameObject placeableIconButton in MinimapReflection.GetPlaceableIconButtons())
				{
					if ((Object)(object)placeableIconButton != (Object)null && !placeableIconButton.activeSelf)
					{
						placeableIconButton.SetActive(true);
					}
				}
				foreach (GameObject systemFilterButton in MinimapReflection.GetSystemFilterButtons())
				{
					if ((Object)(object)systemFilterButton != (Object)null && !systemFilterButton.activeSelf)
					{
						systemFilterButton.SetActive(true);
					}
				}
				if ((Object)(object)Minimap.instance != (Object)null && (Object)(object)Minimap.instance.m_publicPosition != (Object)null && !((Component)Minimap.instance.m_publicPosition).gameObject.activeSelf)
				{
					((Component)Minimap.instance.m_publicPosition).gameObject.SetActive(true);
				}
			}
			catch
			{
			}
		}

		private void OpenWorkbenchAtCursor()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (!MinimapReflection.TryScreenToWorldPoint(Input.mousePosition, out var worldPosition))
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer == null)
				{
					return;
				}
				worldPosition = ((Component)localPlayer).transform.position;
			}
			OpenWorkbenchNear(worldPosition);
		}

		private bool AtlasAccessAllowed(out string denial)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			denial = "";
			try
			{
				if ((Object)(object)ZoneSystem.instance == (Object)null || !ZoneSystem.instance.GetGlobalKey("nomap"))
				{
					return true;
				}
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null && SurveyScanner.AnyInstanceNear("piece_maptable", ((Component)localPlayer).transform.position, 10f))
				{
					return true;
				}
				denial = AtlasStrings.Get("hud.noMapNeedTable");
				return false;
			}
			catch
			{
				return true;
			}
		}

		private void ShowOnboardingOnce()
		{
			if (_onboardingChecked)
			{
				return;
			}
			_onboardingChecked = true;
			try
			{
				string path = Path.Combine(Paths.ConfigPath, "ConcernedCatMods", "ConcernedCartographer", "onboarding-shown.txt");
				if (!File.Exists(path))
				{
					Directory.CreateDirectory(Path.GetDirectoryName(path));
					File.WriteAllText(path, DateTime.UtcNow.ToString("o"));
					Player localPlayer = Player.m_localPlayer;
					if (localPlayer != null)
					{
						((Character)localPlayer).Message((MessageType)2, AtlasStrings.Get("hud.onboarding"), 0, (Sprite)null);
					}
				}
			}
			catch
			{
			}
		}

		private static bool GamepadDown(string buttonName)
		{
			if (string.IsNullOrEmpty(buttonName))
			{
				return false;
			}
			try
			{
				return ZInput.GetButtonDown(buttonName);
			}
			catch
			{
				return false;
			}
		}

		private void OpenWorkbenchNear(Vector3 world)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			if (_pinCommands == null)
			{
				return;
			}
			if (!AtlasAccessAllowed(out string denial))
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)1, denial, 0, (Sprite)null);
				}
				return;
			}
			_workbenchPanel.UiScale = _settings.UiScale.Value;
			RoadPoint other = new RoadPoint(world.x, world.y, world.z);
			PinOperations operations = _pinCommands.Operations;
			Action resync = ResyncPins;
			AtlasPin atlasPin = null;
			float num = 30f;
			foreach (AtlasPin item in _pinStore.Living)
			{
				float num2 = item.Position.HorizontalDistanceTo(in other);
				if (num2 < num)
				{
					num = num2;
					atlasPin = item;
				}
			}
			if (atlasPin != null)
			{
				AtlasPin captured = atlasPin;
				_mapUi.OpenExclusive(_workbenchToken, delegate
				{
					_workbenchPanel.OpenForManaged(captured, operations, resync);
				});
			}
			else
			{
				if (!_pinAdapter.TryFindNearest(world, 30f, out PinData pin, out float _))
				{
					return;
				}
				if (_pinAdapter.IsAdoptableVanilla(pin) && _compatibility.PinManagerPresent)
				{
					_workbenchPanel.OpenReadOnly("\"" + pin.m_name + "\" — another pin manager is installed; use 'cc_pins adopt' to manage this pin here");
				}
				else if (_pinAdapter.IsAdoptableVanilla(pin))
				{
					PinData captured2 = pin;
					_workbenchPanel.OpenAdoptPrompt(captured2.m_name ?? "", () => _pinAdapter.Adopt(_pinStore, captured2), operations, resync);
				}
				else
				{
					_workbenchPanel.OpenReadOnly($"\"{pin.m_name}\" ({pin.m_type})");
				}
			}
		}

		public void SaveAll()
		{
			_drawerPanel.FlushPosition();
			SaveIfDirty();
			SavePinsSnapshot();
			_savedViewPersistence.Save(_savedViews);
		}

		internal string ExecuteAtlasCommand(string[] args)
		{
			if (!AtlasAccessAllowed(out string denial))
			{
				return denial;
			}
			if (_disposed || !_mapReady)
			{
				return "Concerned Cartographer: no world is loaded yet.";
			}
			string text = ((args.Length == 0) ? "status" : args[0].ToLowerInvariant());
			string text2 = ((args.Length > 1) ? string.Join(" ", args, 1, args.Length - 1) : "");
			switch (text)
			{
			case "status":
				return "Atlas view: query \"" + _displayController.QueryText + "\", pins " + (_displayController.ShowPins ? "on" : "off") + ", cluster " + (_displayController.ClusterEnabled ? "on" : "off") + ", dirt " + (_settings.DrawerShowDirt.Value ? "on" : "off") + ", paved " + (_settings.DrawerShowPaved.Value ? "on" : "off") + ". " + $"{_displayController.VisibleCount} shown, {_displayController.HiddenByFilter} filtered, {_displayController.ClusterCount} clusters.";
			case "query":
				_displayController.SetQuery(text2);
				ReapplyDisplay();
				return $"Filter applied: \"{text2}\" — {_displayController.VisibleCount} shown, {_displayController.HiddenByFilter} filtered. Filters are display-only; 'cc_atlas clear' restores everything.";
			case "clear":
				_displayController.SetQuery("");
				ReapplyDisplay();
				return "Filter cleared; all pins shown.";
			case "paved":
			case "dirt":
			case "pins":
			case "cluster":
			{
				if (!TryParseOnOff(text2, out var enabled))
				{
					return "Usage: cc_atlas " + text + " on|off";
				}
				ApplyToggle(text, enabled);
				return text + " " + (enabled ? "on" : "off") + ".";
			}
			case "view":
				return HandleViewCommand(text2);
			case "compat":
				return _compatibility.Report();
			case "backup":
			{
				long? worldUid = _worldUid;
				if (worldUid.HasValue)
				{
					long valueOrDefault = worldUid.GetValueOrDefault();
					return "Backed up to " + _backupTools.Backup(valueOrDefault);
				}
				return "No world loaded.";
			}
			case "backups":
			{
				long? worldUid = _worldUid;
				if (worldUid.HasValue)
				{
					long valueOrDefault3 = worldUid.GetValueOrDefault();
					List<string> list = _backupTools.ListBackups(valueOrDefault3);
					if (list.Count == 0)
					{
						return "No backups yet. 'cc_atlas backup' creates one; exports/imports use the same folders.";
					}
					StringBuilder stringBuilder2 = new StringBuilder($"{list.Count} backup(s), newest first:");
					for (int i = 0; i < list.Count && i < 10; i++)
					{
						stringBuilder2.Append($"\n  {i + 1}. {Path.GetFileName(list[i])}");
					}
					stringBuilder2.Append("\n'cc_atlas restore <n>' restores one (takes a safety backup first).");
					return stringBuilder2.ToString();
				}
				return "No world loaded.";
			}
			case "restore":
			{
				long? worldUid = _worldUid;
				if (worldUid.HasValue)
				{
					long valueOrDefault4 = worldUid.GetValueOrDefault();
					List<string> list2 = _backupTools.ListBackups(valueOrDefault4);
					if (!int.TryParse(text2.Trim(), out var result) || result < 1 || result > list2.Count)
					{
						return "Usage: cc_atlas restore <n>  (see 'cc_atlas backups')";
					}
					return _backupTools.Restore(valueOrDefault4, list2[result - 1]);
				}
				return "No world loaded.";
			}
			case "support":
			{
				long? worldUid = _worldUid;
				if (worldUid.HasValue)
				{
					long valueOrDefault2 = worldUid.GetValueOrDefault();
					string text3 = _backupTools.WriteSupportReport(valueOrDefault2, "0.10.0", $"enabled={_settings.Enabled.Value}, capture={_settings.CaptureConstructionActions.Value}, " + $"reconcile={_settings.ReconcileTerrainChanges.Value}, " + $"survey={_settings.SurveyRulesEnabled.Value}, cluster={_settings.DrawerCluster.Value}, " + $"contrast={_settings.HighContrast.Value}, uiScale={_settings.UiScale.Value}");
					return "Sanitized support report (no positions/names/notes/world ids/paths) written to " + text3;
				}
				return "No world loaded.";
			}
			case "views":
			{
				StringBuilder stringBuilder = new StringBuilder("Saved views:");
				if (_savedViews.Views.Count == 0)
				{
					return "Saved views: none. 'cc_atlas view save <name>' captures the current filter/layer state.";
				}
				foreach (SavedView view in _savedViews.Views)
				{
					stringBuilder.Append("\n  \"" + view.Name + "\" — query \"" + view.Query + "\"");
				}
				return stringBuilder.ToString();
			}
			default:
				return "Usage: cc_atlas [status|query <text>|clear|pins on/off|cluster on/off|dirt on/off|paved on/off|view save/apply/del <name>|views]";
			}
		}

		internal string ExecuteSurveyCommand(string[] args)
		{
			if (!AtlasAccessAllowed(out string denial))
			{
				return denial;
			}
			if (_disposed || !_mapReady)
			{
				return "Concerned Cartographer: no world is loaded yet.";
			}
			string text = ((args.Length == 0) ? "status" : args[0].ToLowerInvariant());
			string text2 = ((args.Length > 1) ? args[1].ToLowerInvariant() : "");
			string text3 = ((args.Length > 1) ? args[1] : "");
			IReadOnlyList<SurveyEngine.Observation> observations = _surveyEngine.Observations;
			switch (text)
			{
			case "status":
				return "Survey: " + (_settings.SurveyRulesEnabled.Value ? "ENABLED" : "disabled (Survey/SurveyRulesEnabled)") + ", " + $"{_surveyEngine.Rules.Rules.Count} rule(s), {_surveyEngine.Rules.Blacklist.Count} blacklist pattern(s), " + $"{observations.Count} pending observation(s). Rules file: {SurveyRulePersistence.RulePath}";
			case "list":
			{
				if (observations.Count == 0)
				{
					return "No pending observations.";
				}
				StringBuilder stringBuilder = new StringBuilder($"{observations.Count} observation(s):");
				for (int i = 0; i < observations.Count && i < 15; i++)
				{
					SurveyEngine.Observation observation = observations[i];
					stringBuilder.Append($"\n  {i + 1}. {observation.SuggestedName} [{observation.Category}] at ({observation.Position.X:0}, {observation.Position.Z:0})");
				}
				if (observations.Count > 15)
				{
					stringBuilder.Append($"\n  ... and {observations.Count - 15} more.");
				}
				stringBuilder.Append("\ncc_survey accept <n|all> / reject <n|all>");
				return stringBuilder.ToString();
			}
			case "accept":
			{
				if (text2 == "all")
				{
					int num3 = _surveyEngine.AcceptAll(_pinStore, delegate(AtlasPin atlasPin)
					{
						_displayController.MarkStickyVisible(atlasPin.Id);
					});
					ResyncPins();
					return $"Accepted {num3} observation(s) as markers.";
				}
				Guid? guid = null;
				int result3;
				if (text3.StartsWith("id:", StringComparison.OrdinalIgnoreCase) && Guid.TryParse(text3.Substring(3), out var result2))
				{
					guid = result2;
				}
				else if (int.TryParse(text2, out result3) && result3 >= 1 && result3 <= observations.Count)
				{
					guid = observations[result3 - 1].Id;
				}
				if (guid.HasValue)
				{
					Guid valueOrDefault = guid.GetValueOrDefault();
					if (!_surveyEngine.Accept(valueOrDefault, _pinStore, out AtlasPin created))
					{
						return "That observation is no longer pending — the list just updated.";
					}
					if (created != null)
					{
						_displayController.MarkStickyVisible(created.Id);
					}
					ResyncPins();
					return "Accepted \"" + created?.Name + "\" as a marker.";
				}
				return "Usage: cc_survey accept <n|all>";
			}
			case "reject":
			{
				if (text2 == "all")
				{
					int num6 = _surveyEngine.RejectAll(DateTime.UtcNow);
					SaveRejectedIfDirty();
					return $"Rejected {num6} observation(s); they moved to the Rejected list.";
				}
				Guid? guid2 = null;
				int result7;
				if (text3.StartsWith("id:", StringComparison.OrdinalIgnoreCase) && Guid.TryParse(text3.Substring(3), out var result6))
				{
					guid2 = result6;
				}
				else if (int.TryParse(text2, out result7) && result7 >= 1 && result7 <= observations.Count)
				{
					guid2 = observations[result7 - 1].Id;
				}
				if (guid2.HasValue)
				{
					Guid valueOrDefault2 = guid2.GetValueOrDefault();
					if (!_surveyEngine.Reject(valueOrDefault2, DateTime.UtcNow))
					{
						return "That observation is no longer pending — the list just updated.";
					}
					SaveRejectedIfDirty();
					return "Rejected; it moved to the Rejected list.";
				}
				return "Usage: cc_survey reject <n|all>";
			}
			case "rejected":
			{
				if (_surveyEngine.Rejected.Count == 0)
				{
					return "The Rejected list is empty.";
				}
				StringBuilder stringBuilder2 = new StringBuilder($"{_surveyEngine.Rejected.Count} rejected:");
				for (int num4 = 0; num4 < _surveyEngine.Rejected.Count && num4 < 15; num4++)
				{
					SurveyEngine.RejectedObservation rejectedObservation = _surveyEngine.Rejected[num4];
					stringBuilder2.Append($"\n  {num4 + 1}. {rejectedObservation.SuggestedName} [{rejectedObservation.Category}] at ({rejectedObservation.Position.X:0}, {rejectedObservation.Position.Z:0})");
				}
				if (_surveyEngine.Rejected.Count > 15)
				{
					stringBuilder2.Append($"\n  ... and {_surveyEngine.Rejected.Count - 15} more.");
				}
				return stringBuilder2.ToString();
			}
			case "restore":
			{
				if (text2 == "all")
				{
					int num = _surveyEngine.RestoreAllRejected(DateTime.UtcNow);
					SaveRejectedIfDirty();
					return $"Restored {num} rejected observation(s) to pending review.";
				}
				int num2 = -1;
				int result;
				if (text3.StartsWith("key:", StringComparison.OrdinalIgnoreCase))
				{
					num2 = _surveyEngine.FindRejectedIndex(text3.Substring(4));
					if (num2 < 0)
					{
						return "That rejected entry is no longer listed — the list just updated.";
					}
				}
				else if (int.TryParse(text2, out result))
				{
					num2 = result - 1;
				}
				if (num2 >= 0 && _surveyEngine.RestoreRejected(num2, DateTime.UtcNow))
				{
					SaveRejectedIfDirty();
					return "Restored the rejected entry to pending review.";
				}
				return "Usage: cc_survey restore <n|all>";
			}
			case "acceptrejected":
			{
				int num5 = -1;
				int result5;
				if (text3.StartsWith("key:", StringComparison.OrdinalIgnoreCase))
				{
					num5 = _surveyEngine.FindRejectedIndex(text3.Substring(4));
					if (num5 < 0)
					{
						return "That rejected entry is no longer listed — the list just updated.";
					}
				}
				else if (int.TryParse(text2, out result5))
				{
					num5 = result5 - 1;
				}
				if (num5 >= 0 && _surveyEngine.AcceptRejected(num5, _pinStore, out AtlasPin created2))
				{
					if (created2 != null)
					{
						_displayController.MarkStickyVisible(created2.Id);
					}
					ResyncPins();
					SaveRejectedIfDirty();
					return "Accepted \"" + created2?.Name + "\" as a marker.";
				}
				return "Usage: cc_survey acceptrejected <n>";
			}
			case "rules":
			{
				if (_surveyEngine.Rules.Rules.Count == 0)
				{
					return "No survey rules. Add one from the Survey panel's Rules view.";
				}
				StringBuilder stringBuilder3 = new StringBuilder($"{_surveyEngine.Rules.Rules.Count} rule(s):");
				for (int num7 = 0; num7 < _surveyEngine.Rules.Rules.Count; num7++)
				{
					SurveyRule surveyRule2 = _surveyEngine.Rules.Rules[num7];
					stringBuilder3.Append(string.Format("\n  {0}. [{1}] {2} → {3} ({4})", num7 + 1, surveyRule2.Enabled ? "on " : "OFF", surveyRule2.Pattern, surveyRule2.Category, surveyRule2.IconId));
				}
				return stringBuilder3.ToString();
			}
			case "ruleon":
			case "ruleoff":
			{
				if (int.TryParse(text2, out var result4))
				{
					SurveyRule surveyRule = _surveyEngine.Rules.SetRuleEnabled(result4 - 1, text == "ruleon");
					if (surveyRule != null)
					{
						_surveyRulePersistence.Save(_surveyEngine.Rules);
						return "Rule \"" + surveyRule.Pattern + "\" is now " + (surveyRule.Enabled ? "enabled" : "disabled") + ".";
					}
				}
				return "Usage: cc_survey ruleon <n> / ruleoff <n>";
			}
			case "ruledel":
			{
				if (int.TryParse(text2, out var result8))
				{
					SurveyRule surveyRule3 = _surveyEngine.Rules.RemoveRuleAt(result8 - 1);
					if (surveyRule3 != null)
					{
						_surveyRulePersistence.Save(_surveyEngine.Rules);
						return "Removed rule \"" + surveyRule3.Pattern + "\".";
					}
				}
				return "Usage: cc_survey ruledel <n>";
			}
			case "ruleadd":
			{
				string text4 = SurveyRuleSet.Clean(text2);
				if (text4.Length == 0 || text4 == "*")
				{
					return "Usage: cc_survey ruleadd <prefab-pattern> ('bush*' matches prefixes)";
				}
				string text5 = ((args.Length > 2) ? args[2] : "cc:resource");
				string text6 = ((args.Length > 3) ? string.Join(" ", args, 3, args.Length - 3) : "Resources");
				_surveyEngine.Rules.AddRule(new SurveyRule(text4, text5, text6, 30f, 120f));
				_surveyRulePersistence.Save(_surveyEngine.Rules);
				return "Added rule \"" + text4 + "\" → " + text6 + " (" + text5 + ").";
			}
			case "reload":
				_surveyEngine.Rules = _surveyRulePersistence.LoadOrCreate();
				return $"Reloaded {_surveyEngine.Rules.Rules.Count} rule(s) and {_surveyEngine.Rules.Blacklist.Count} blacklist pattern(s).";
			case "path":
				return SurveyRulePersistence.RulePath + " (the file is the shareable import/export format)";
			default:
				return "Usage: cc_survey [status|list|accept <n|all>|reject <n|all>|rejected|restore <n|all>|acceptrejected <n>|rules|ruleon/ruleoff/ruledel <n>|ruleadd <pattern> [icon] [category]|reload|path]";
			}
		}

		private void SaveRejectedIfDirty()
		{
			if (!_surveyEngine.RejectedDirty)
			{
				return;
			}
			long? worldUid = _worldUid;
			if (worldUid.HasValue)
			{
				long valueOrDefault = worldUid.GetValueOrDefault();
				if (_surveyRejectedPersistence.Save(valueOrDefault, _surveyEngine.Rejected))
				{
					_surveyEngine.MarkRejectedClean();
				}
			}
		}

		private string HandleViewCommand(string remainder)
		{
			int num = remainder.IndexOf(' ');
			string text = ((num < 0) ? remainder : remainder.Substring(0, num)).ToLowerInvariant();
			string text2 = ((num < 0) ? "" : remainder.Substring(num + 1).Trim());
			if (text2.Length == 0)
			{
				return "Usage: cc_atlas view save|apply|del <name>";
			}
			switch (text)
			{
			case "save":
				_drawerPanel.ViewSaved?.Invoke(text2);
				return "View \"" + text2 + "\" saved with the current filter and layer state.";
			case "apply":
				if (!ApplySavedView(text2))
				{
					return "No view named \"" + text2 + "\".";
				}
				return "View \"" + text2 + "\" applied.";
			case "del":
			{
				bool num2 = _savedViews.Remove(text2);
				_savedViewPersistence.Save(_savedViews);
				if (!num2)
				{
					return "No view named \"" + text2 + "\".";
				}
				return "View \"" + text2 + "\" deleted.";
			}
			default:
				return "Usage: cc_atlas view save|apply|del <name>";
			}
		}

		private void ApplyToggle(string which, bool enabled)
		{
			switch (which)
			{
			case "pins":
				_settings.DrawerShowPins.Value = enabled;
				_displayController.ShowPins = enabled;
				ReapplyDisplay();
				break;
			case "cluster":
				_settings.DrawerCluster.Value = enabled;
				_displayController.ClusterEnabled = enabled;
				ReapplyDisplay();
				break;
			case "dirt":
				_settings.DrawerShowDirt.Value = enabled;
				_renderer.SetOverlayEnabled(RoadKind.Dirt, enabled);
				break;
			case "paved":
				_settings.DrawerShowPaved.Value = enabled;
				_renderer.SetOverlayEnabled(RoadKind.Paved, enabled);
				break;
			}
		}

		private static bool TryParseOnOff(string text, out bool enabled)
		{
			switch (text.Trim().ToLowerInvariant())
			{
			case "on":
			case "true":
			case "1":
				enabled = true;
				return true;
			case "off":
			case "false":
			case "0":
				enabled = false;
				return true;
			default:
				enabled = false;
				return false;
			}
		}

		private void SavePinsSnapshot()
		{
			long? worldUid = _worldUid;
			if (worldUid.HasValue)
			{
				long valueOrDefault = worldUid.GetValueOrDefault();
				_pinPersistence.Save(valueOrDefault, _pinStore);
				_routePersistence.Save(valueOrDefault, _routeStore);
			}
		}

		internal string ExecuteSyncCommand(string[] args)
		{
			if (!AtlasAccessAllowed(out string denial))
			{
				return denial;
			}
			if (_disposed || !_mapReady)
			{
				return "Concerned Cartographer: no world is loaded yet.";
			}
			string text = ((args.Length == 0) ? "status" : args[0].ToLowerInvariant());
			string text2 = ((args.Length > 1) ? string.Join(" ", args, 1, args.Length - 1).Trim() : "");
			switch (text)
			{
			case "status":
				var (list3, list4) = SyncPlanner.CollectShared(_pinStore, _routeStore);
				return $"Sync: sharing {list3.Count} pin(s) and {list4.Count} route(s) " + $"(scope table/server, tombstones included). Inbox: {_syncInbox.Envelopes.Count} pending share(s). " + "Set a pin/route scope with 'cc_pins scope table' or 'cc_routes ...' to share it; 'cc_sync share' broadcasts.";
			case "share":
			{
				var (list, list2) = SyncPlanner.CollectShared(_pinStore, _routeStore);
				if (list.Count == 0 && list2.Count == 0)
				{
					return "Nothing is scoped for sharing yet. 'cc_pins scope table' near a pin shares it.";
				}
				Player localPlayer = Player.m_localPlayer;
				string authorName = ((localPlayer != null) ? localPlayer.GetPlayerName() : null) ?? "";
				_syncTransport.Share(_authorId, authorName, list, list2, out string message);
				_log.LogInfo((object)("Sync share: " + message));
				return message;
			}
			case "inbox":
			{
				if (_syncInbox.Envelopes.Count == 0)
				{
					return "Sync inbox: empty.";
				}
				StringBuilder stringBuilder = new StringBuilder("Sync inbox:");
				foreach (SyncInbox.Envelope envelope3 in _syncInbox.Envelopes)
				{
					stringBuilder.Append($"\n  {envelope3.AuthorName}: {envelope3.Pins.Count} pin(s), {envelope3.Routes.Count} route(s) " + $"at {envelope3.ReceivedUtc:HH:mm} UTC — 'cc_sync preview {envelope3.AuthorName}'");
				}
				return stringBuilder.ToString();
			}
			case "preview":
			{
				if (!_syncInbox.TryPeek(text2, out SyncInbox.Envelope envelope2))
				{
					return "No pending share from \"" + text2 + "\". 'cc_sync inbox' lists them.";
				}
				SyncPlan syncPlan2 = SyncPlanner.Plan(_pinStore, _routeStore, envelope2.Pins, envelope2.Routes);
				List<string> list5 = syncPlan2.DeletionNames(10);
				string text4 = ((list5.Count == 0) ? "" : ("\n  Would DELETE: " + string.Join(", ", list5) + ((syncPlan2.TombstonePins.Count + syncPlan2.TombstoneRoutes.Count > list5.Count) ? $" (+{syncPlan2.TombstonePins.Count + syncPlan2.TombstoneRoutes.Count - list5.Count} more)" : "")));
				return "Share from " + envelope2.AuthorName + ": " + syncPlan2.Summary() + "." + text4 + ((syncPlan2.PinConflicts.Count + syncPlan2.RouteConflicts.Count > 0) ? (" Apply with 'cc_sync apply " + envelope2.AuthorName + " mine' (keep local on conflicts) or '... theirs'.") : (" Apply with 'cc_sync apply " + envelope2.AuthorName + "'."));
			}
			case "apply":
			{
				string[] array = text2.Split(new char[1] { ' ' });
				bool flag = array.Length > 1 && string.Equals(array[^1], "theirs", StringComparison.OrdinalIgnoreCase);
				string text3 = ((flag || (array.Length > 1 && string.Equals(array[^1], "mine", StringComparison.OrdinalIgnoreCase))) ? string.Join(" ", array, 0, array.Length - 1) : text2);
				if (!_syncInbox.TryTake(text3, out SyncInbox.Envelope envelope))
				{
					return "No pending share from \"" + text3 + "\".";
				}
				SyncPlan syncPlan = SyncPlanner.Plan(_pinStore, _routeStore, envelope.Pins, envelope.Routes);
				int num = SyncPlanner.Apply(syncPlan, _pinStore, _routeStore, flag);
				ResyncPins();
				_routeRedrawPending = true;
				SavePinsSnapshot();
				_log.LogInfo((object)$"Sync apply: {num} change(s); {syncPlan.Summary()}");
				return $"Applied {num} change(s) from {envelope.AuthorName} " + "(" + (flag ? "conflicts took their side" : "conflicts kept your side") + "). " + syncPlan.Summary();
			}
			case "clear":
				_syncInbox.Clear();
				return "Sync inbox cleared.";
			default:
				return "Usage: cc_sync [status|share|inbox|preview <author>|apply <author> [mine|theirs]|clear]";
			}
		}

		internal string ExecuteRouteCommand(string[] args)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (!AtlasAccessAllowed(out string denial))
			{
				return denial;
			}
			if (_disposed || !_mapReady || _routeCommands == null)
			{
				return "Concerned Cartographer: no world is loaded yet.";
			}
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer == null)
			{
				return "Concerned Cartographer: no local player.";
			}
			return _routeCommands.Execute(args, ((Component)localPlayer).transform.position);
		}

		private void HandleTerrainOperation(CapturedTerrainOperation operation)
		{
			//IL_0087: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			if (_disposed || !_settings.Enabled.Value || !_mapReady || _pipeline == null)
			{
				return;
			}
			long? worldUid = _worldUid;
			if (!worldUid.HasValue)
			{
				return;
			}
			_rateLimited.Info("terrain-action-" + operation.Category, $"Terrain action classified: {operation.ActionDescription} r={operation.RadiusMeters:0.#}m.");
			RoadPoint center = new RoadPoint(operation.Position.x, operation.Position.y, operation.Position.z);
			float radiusMeters = operation.RadiusMeters + 1f;
			if (!operation.RoadKind.HasValue)
			{
				int num = _terrainIntent.AddExclusion(center.X, center.Z, radiusMeters);
				if (num > 0 && _settings.DebugLogging.Value)
				{
					_rateLimited.Info("terrain-intent-add", $"Terraforming r={operation.RadiusMeters:0.#}m: " + $"{num} cell(s) marked not-road ({_terrainIntent.Count} total).");
				}
			}
			else
			{
				_terrainIntent.ClearExclusion(center.X, center.Z, radiusMeters);
			}
			RoadKind? roadKind;
			if (_settings.ReconcileTerrainChanges.Value)
			{
				int num2 = 0;
				roadKind = operation.RoadKind;
				if (roadKind.HasValue)
				{
					RoadKind valueOrDefault = roadKind.GetValueOrDefault();
					RoadKind kind = ((valueOrDefault != RoadKind.Dirt) ? RoadKind.Dirt : RoadKind.Paved);
					num2 = RemoveCoverageWithBackup(kind, center, operation.RadiusMeters);
				}
				else
				{
					num2 = RemoveCoverageWithBackup(RoadKind.Dirt, center, operation.RadiusMeters) + RemoveCoverageWithBackup(RoadKind.Paved, center, operation.RadiusMeters);
				}
				if (num2 > 0)
				{
					_redrawPending = true;
					_log.LogInfo((object)("Reconciled a terrain change (" + operation.ActionDescription + ") " + $"r={operation.RadiusMeters:0.#}m: removed {num2} road point(s)."));
				}
			}
			roadKind = operation.RoadKind;
			if (roadKind.HasValue)
			{
				RoadKind valueOrDefault2 = roadKind.GetValueOrDefault();
				if (_settings.CaptureConstructionActions.Value)
				{
					ObserveAndDraw(rules: new RoadSamplingRules(_settings.MinimumPointSpacingMeters.Value, _settings.MaximumStrokeGapMeters.Value, _settings.DuplicateSuppressionMeters.Value), source: RoadObservationSource.Construction, kind: valueOrDefault2, position: operation.Position, debugKey: "construction-observed");
				}
			}
		}

		private int RemoveCoverageWithBackup(RoadKind kind, RoadPoint center, float radiusMeters)
		{
			_persistence.BackupBeforeReconciliation(_worldUid.Value);
			return _atlas.RemoveCoverage(kind, center, radiusMeters);
		}

		private void ObserveAndDraw(RoadObservationSource source, RoadKind kind, Vector3 position, RoadSamplingRules rules, string debugKey)
		{
			//IL_002f: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			if (!_disposed && _settings.Enabled.Value && _mapReady && _pipeline != null)
			{
				RoadObservation observation = new RoadObservation(source, kind, new RoadPoint(position.x, position.y, position.z));
				int pointCount = _atlas.PointCount;
				if (_pipeline.Observe(in observation, rules, out var segment))
				{
					_renderer.DrawSegment(segment);
				}
				else if (_atlas.PointCount > pointCount)
				{
					_renderer.DrawPoint(kind, observation.Position);
				}
				if (_settings.DebugLogging.Value)
				{
					_rateLimited.Info(debugKey, $"Observed {observation.Source}/{observation.Kind}.");
				}
			}
		}

		internal string ExecuteRoadCommand(string[] args)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_006a: 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_054f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ec: Unknown result type (might be due to invalid IL or missing references)
			if (!AtlasAccessAllowed(out string denial))
			{
				return denial;
			}
			if (!_disposed && _mapReady && _editor != null)
			{
				long? worldUid = _worldUid;
				if (worldUid.HasValue)
				{
					Player localPlayer = Player.m_localPlayer;
					if (localPlayer == null)
					{
						return "Concerned Cartographer: no local player.";
					}
					Vector3 position = ((Component)localPlayer).transform.position;
					RoadPoint position2 = new RoadPoint(position.x, position.y, position.z);
					string text = ((args.Length == 0) ? "status" : args[0].ToLowerInvariant());
					float radius = 10f;
					if (args.Length > 1 && float.TryParse(args[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
					{
						radius = Mathf.Clamp(result, 1f, 100f);
					}
					bool flag;
					string summary;
					switch (text)
					{
					case "status":
					{
						int num3 = 0;
						foreach (RoadStroke stroke in _atlas.Strokes)
						{
							if (stroke.Hidden)
							{
								num3++;
							}
						}
						return $"Atlas: {_atlas.Strokes.Count} road(s), {_atlas.PointCount} point(s), " + $"{num3} hidden, undo depth {_editor.UndoCount}. {_editor.DescribeNearest(position2, radius)}";
					}
					case "delete":
						flag = MutateWithBackup(() => _editor.DeleteNearest(position2, radius, out _lastToolSummary));
						summary = _lastToolSummary;
						break;
					case "kind":
						flag = MutateWithBackup(() => _editor.ReclassifyNearest(position2, radius, out _lastToolSummary));
						summary = _lastToolSummary;
						break;
					case "hide":
						flag = MutateWithBackup(() => _editor.SetHiddenNearest(position2, radius, hidden: true, out _lastToolSummary));
						summary = _lastToolSummary;
						break;
					case "unhide":
						flag = MutateWithBackup(() => _editor.SetHiddenNearest(position2, radius, hidden: false, out _lastToolSummary));
						summary = _lastToolSummary;
						break;
					case "split":
						flag = MutateWithBackup(() => _editor.SplitNearest(position2, radius, out _lastToolSummary));
						summary = _lastToolSummary;
						break;
					case "join":
						flag = MutateWithBackup(() => _editor.JoinNearest(position2, radius, out _lastToolSummary));
						summary = _lastToolSummary;
						break;
					case "rebuild":
					{
						float num = ((args.Length > 1) ? radius : 32f);
						_persistence.BackupBeforeReconciliation(_worldUid.Value);
						int num2 = _atlas.RemoveCoverage(RoadKind.Dirt, position2, num) + _atlas.RemoveCoverage(RoadKind.Paved, position2, num);
						flag = num2 > 0;
						summary = $"Cleared {num2} road point(s) within {num:0.#} m. " + "Roads return only when you Pathen/Pave the ground again ('cc_roads undo' reverts).";
						break;
					}
					case "undo":
						flag = _editor.Undo(out summary);
						break;
					case "align":
						if (args.Length > 1 && string.Equals(args[1], "clear", StringComparison.OrdinalIgnoreCase))
						{
							_renderer.ClearAlignmentProbe();
							_renderer.RedrawAll(_atlas);
							_redrawPending = false;
							return "Alignment markers removed.";
						}
						if (args.Length > 1 && string.Equals(args[1], "live", StringComparison.OrdinalIgnoreCase))
						{
							RoadKind kind;
							bool standingOnRoad = _probe.TryClassify(position, out kind);
							RoadPoint nearest;
							float distanceMeters;
							bool hasNearest = _atlas.TryGetNearestPointOnRoads(position2, 50f, out nearest, out distanceMeters);
							string result2 = LiveAlignmentProbe.BuildReport(position, standingOnRoad, kind, _surveyor?.LatestSample, _pipeline?.LastAccepted, hasNearest, nearest, distanceMeters, _renderer);
							_log.LogInfo((object)"cc_roads align live: diagnostic report written to the console (positions are never logged).");
							return result2;
						}
						return _renderer.RunAlignmentProbe(position, _atlas);
					default:
						return "Usage: cc_roads [status|delete|kind|hide|unhide|split|join|rebuild|undo] [radius].";
					}
					if (flag)
					{
						_redrawPending = true;
						SaveIfDirty();
						_log.LogInfo((object)("Road tool '" + text + "': " + summary));
					}
					return summary;
				}
			}
			return "Concerned Cartographer: no world is loaded yet.";
		}

		private bool MutateWithBackup(Func<bool> operation)
		{
			_persistence.BackupBeforeReconciliation(_worldUid.Value);
			return operation();
		}

		public void SaveIfDirty()
		{
			long? worldUid = _worldUid;
			if (worldUid.HasValue)
			{
				if (_atlas.IsDirty && _persistence.Save(_worldUid.Value, _atlas))
				{
					_atlas.MarkClean();
				}
				if (_terrainIntent.IsDirty && _terrainIntentPersistence.Save(_worldUid.Value, _terrainIntent))
				{
					_terrainIntent.MarkClean();
				}
			}
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_workbenchPanel.Close();
				RestoreVanillaPalette();
				_overlayRelabel.Restore();
				_textFocusBlock.Release();
				_quickPinGate.Disarm();
				MapInputGate.Uninstall();
				PlayerInputGate.Uninstall();
				PinDeletionWatch.Uninstall();
				MapPointerGuard.Clear();
				SaveIfDirty();
				SavePinsSnapshot();
				SaveRejectedIfDirty();
				_pipeline?.EndAllStrokes();
				_constructionCapture.OperationCaptured -= HandleTerrainOperation;
				_constructionCapture.Dispose();
				_disposed = true;
			}
		}

		private void SwitchWorld(long uid)
		{
			if (_worldUid != uid || _surveyor == null)
			{
				SaveRejectedIfDirty();
				SaveIfDirty();
				SavePinsSnapshot();
				_worldUid = uid;
				_atlas = _persistence.Load(uid);
				_terrainIntent = _terrainIntentPersistence.Load(uid);
				_pinStore = _pinPersistence.Load(uid);
				_surveyEngine.ResetSession();
				_surveyEngine.LoadRejected(_surveyRejectedPersistence.Load(uid));
				_pinStore.LocalAuthor = _authorId;
				_pinStore.Changed += _pinPersistence.QueueJournal;
				_pinAdapter.Reset();
				_pinCommands = new PinCommandHandler(_pinStore, new PinOperations(_pinStore), _pinAdapter, _log, ResyncPins);
				_displayController.Reset();
				_routeStore = _routePersistence.Load(uid);
				_routeStore.LocalAuthor = _authorId;
				_routeStore.Changed += _routePersistence.QueueJournal;
				_syncInbox.Clear();
				_routeCommands = new RouteCommandHandler(_routeStore, new RouteOperations(_routeStore), _atlas, _settings, _log, delegate
				{
					_routeRedrawPending = true;
				});
				_pipeline = new RoadObservationPipeline(_atlas, _terrainIntent);
				_editor = new RoadAtlasEditor(_atlas);
				_surveyor = new RoadSurveyor(_settings, _probe, _atlas, _log);
				_redrawPending = false;
				_autosaveElapsed = 0f;
			}
		}
	}
	internal sealed class CartographerSettings
	{
		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<bool> CaptureConstructionActions { get; }

		public ConfigEntry<bool> ReconcileTerrainChanges { get; }

		public ConfigEntry<float> SampleIntervalSeconds { get; }

		public ConfigEntry<float> MinimumPointSpacingMeters { get; }

		public ConfigEntry<float> MaximumStrokeGapMeters { get; }

		public ConfigEntry<float> DuplicateSuppressionMeters { get; }

		public ConfigEntry<float> AutosaveIntervalSeconds { get; }

		public ConfigEntry<float> PaintThreshold { get; }

		public ConfigEntry<int> PaintSampleRadius { get; }

		public ConfigEntry<int> LineWidthPixels { get; }

		public ConfigEntry<bool> DebugLogging { get; }

		public ConfigEntry<bool> DrawCalibrationMarkers { get; }

		public ConfigEntry<KeyCode> WorkbenchHotkey { get; }

		public ConfigEntry<KeyCode> DrawerHotkey { get; }

		public ConfigEntry<bool> DrawerShowDirt { get; }

		public ConfigEntry<bool> DrawerShowPaved { get; }

		public ConfigEntry<bool> DrawerShowPins { get; }

		public ConfigEntry<bool> DrawerCluster { get; }

		public ConfigEntry<string> DrawerPanelPosition { get; }

		public ConfigEntry<KeyCode> QuickPinHotkey { get; }

		public ConfigEntry<float> QuickPinDuplicateRadius { get; }

		public ConfigEntry<bool> SurveyRulesEnabled { get; }

		public ConfigEntry<float> SurveyScanIntervalSeconds { get; }

		public ConfigEntry<float> SurveyScanRadius { get; }

		public ConfigEntry<float> SurveyBaseExclusionRadius { get; }

		public ConfigEntry<int> SurveyMaxObservations { get; }

		public ConfigEntry<KeyCode> RouteDrawModifier { get; }

		public ConfigEntry<float> RouteEraseRadius { get; }

		public ConfigEntry<float> RouteSnapRadius { get; }

		public ConfigEntry<float> RouteOnRoadTolerance { get; }

		public ConfigEntry<float> RouteOffRoadSpeed { get; }

		public ConfigEntry<float> RouteOnRoadSpeed { get; }

		public ConfigEntry<float> UiScale { get; }

		public ConfigEntry<bool> HighContrast { get; }

		public ConfigEntry<string> WorkbenchGamepadButton { get; }

		public ConfigEntry<string> DrawerGamepadButton { get; }

		public ConfigEntry<bool> EnhancedPinPalette { get; }

		public ConfigEntry<bool> ShowVanillaPinPalette { get; }

		public ConfigEntry<CrashConsentState> CrashReportingConsent { get; }

		public ConfigEntry<int> AcceptedPrivacyPolicyVersion { get; }

		public ConfigEntry<string> SentryDsn { get; }

		public ConfigEntry<bool> ShowVanillaMapControls { get; }

		public ConfigEntry<bool> HighPrecisionLargeMapRoads { get; }

		private CartographerSettings(ConfigEntry<bool> enabled, ConfigEntry<bool> captureConstructionActions, ConfigEntry<bool> reconcileTerrainChanges, ConfigEntry<float> sampleIntervalSeconds, ConfigEntry<float> minimumPointSpacingMeters, ConfigEntry<float> maximumStrokeGapMeters, ConfigEntry<float> duplicateSuppressionMeters, ConfigEntry<float> autosaveIntervalSeconds, ConfigEntry<float> paintThreshold, ConfigEntry<int> paintSampleRadius, ConfigEntry<int> lineWidthPixels, ConfigEntry<bool> debugLogging, ConfigEntry<bool> drawCalibrationMarkers, ConfigEntry<KeyCode> workbenchHotkey, ConfigEntry<KeyCode> drawerHotkey, ConfigEntry<bool> drawerShowDirt, ConfigEntry<bool> drawerShowPaved, ConfigEntry<bool> drawerShowPins, ConfigEntry<bool> drawerCluster, ConfigEntry<string> drawerPanelPosition, ConfigEntry<KeyCode> quickPinHotkey, ConfigEntry<float> quickPinDuplicateRadius, ConfigEntry<bool> surveyRulesEnabled, ConfigEntry<float> surveyScanIntervalSeconds, ConfigEntry<float> surveyScanRadius, ConfigEntry<float> surveyBaseExclusionRadius, ConfigEntry<int> surveyMaxObservations, ConfigEntry<KeyCode> routeDrawModifier, ConfigEntry<float> routeEraseRadius, ConfigEntry<float> routeSnapRadius, ConfigEntry<float> routeOnRoadTolerance, ConfigEntry<float> routeOffRoadSpeed, ConfigEntry<float> routeOnRoadSpeed, ConfigEntry<float> uiScale, ConfigEntry<bool> highContrast, ConfigEntry<string> workbenchGamepadButton, ConfigEntry<string> drawerGamepadButton, ConfigEntry<bool> enhancedPinPalette, ConfigEntry<bool> showVanillaPinPalette, ConfigEntry<CrashConsentState> crashReportingConsent, ConfigEntry<int> acceptedPrivacyPolicyVersion, ConfigEntry<string> sentryDsn, ConfigEntry<bool> showVanillaMapControls, ConfigEntry<bool> highPrecisionLargeMapRoads)
		{
			Enabled = enabled;
			CaptureConstructionActions = captureConstructionActions;
			ReconcileTerrainChanges = reconcileTerrainChanges;
			SampleIntervalSeconds = sampleIntervalSeconds;
			MinimumPointSpacingMeters = minimumPointSpacingMeters;
			MaximumStrokeGapMeters = maximumStrokeGapMeters;
			DuplicateSuppressionMeters = duplicateSuppressionMeters;
			AutosaveIntervalSeconds = autosaveIntervalSeconds;
			PaintThreshold = paintThreshold;
			PaintSampleRadius = paintSampleRadius;
			LineWidthPixels = lineWidthPixels;
			DebugLogging = debugLogging;
			DrawCalibrationMarkers = drawCalibrationMarkers;
			WorkbenchHotkey = workbenchHotkey;
			DrawerHotkey = drawerHotkey;
			DrawerShowDirt = drawerShowDirt;
			DrawerShowPaved = drawerShowPaved;
			DrawerShowPins = drawerShowPins;
			DrawerCluster = drawerCluster;
			DrawerPanelPosition = drawerPanelPosition;
			QuickPinHotkey = quickPinHotkey;
			QuickPinDuplicateRadius = quickPinDuplicateRadius;
			SurveyRulesEnabled = surveyRulesEnabled;
			SurveyScanIntervalSeconds = surveyScanIntervalSeconds;
			SurveyScanRadius = surveyScanRadius;
			SurveyBaseExclusionRadius = surveyBaseExclusionRadius;
			SurveyMaxObservations = surveyMaxObservations;
			RouteDrawModifier = routeDrawModifier;
			RouteEraseRadius = routeEraseRadius;
			RouteSnapRadius = routeSnapRadius;
			RouteOnRoadTolerance = routeOnRoadTolerance;
			RouteOffRoadSpeed = routeOffRoadSpeed;
			RouteOnRoadSpeed = routeOnRoadSpeed;
			UiScale = uiScale;
			HighContrast = highContrast;
			WorkbenchGamepadButton = workbenchGamepadButton;
			DrawerGamepadButton = drawerGamepadButton;
			EnhancedPinPalette = enhancedPinPalette;
			ShowVanillaPinPalette = showVanillaPinPalette;
			CrashReportingConsent = crashReportingConsent;
			AcceptedPrivacyPolicyVersion = acceptedPrivacyPolicyVersion;
			SentryDsn = sentryDsn;
			ShowVanillaMapControls = showVanillaMapControls;
			HighPrecisionLargeMapRoads = highPrecisionLargeMapRoads;
		}

		public static CartographerSettings Bind(ConfigFile config)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Expected O, but got Unknown
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Expected O, but got Unknown
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Expected O, but got Unknown
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Expected O, but got Unknown
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Expected O, but got Unknown
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Expected O, but got Unknown
			//IL_034d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0357: Expected O, but got Unknown
			//IL_0380: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Expected O, but got Unknown
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Expected O, but got Unknown
			//IL_03fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0407: Expected O, but got Unknown
			//IL_0430: Unknown result type (might be due to invalid IL or missing references)
			//IL_043a: Expected O, but got Unknown
			//IL_0463: Unknown result type (might be due to invalid IL or missing references)
			//IL_046d: Expected O, but got Unknown
			//IL_0496: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a0: Expected O, but got Unknown
			//IL_04c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d3: Expected O, but got Unknown
			//IL_04fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0506: Expected O, but got Unknown
			return new CartographerSettings(config.Bind<bool>("General", "Enabled", true, "Enable road surveying and map overlays."), config.Bind<bool>("Sources", "CaptureConstructionActions", true, "Record roads from your own successful Pathen (hoe) and Paved (cultivator/stonecutter) actions. This is the ONLY road source: walking existing paint never creates roads."), config.Bind<bool>("Sources", "ReconcileTerrainChanges", true, "When you level, raise, cultivate, reset, or repaint terrain, remove the covered road ink from the atlas so no ghost roads remain."), config.Bind<float>("Survey", "SampleIntervalSeconds", 0.35f, new ConfigDescription("Seconds between diagnostic terrain samples under the player (feeds 'cc_roads align live'; never creates roads).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>())), config.Bind<float>("Survey", "MinimumPointSpacingMeters", 1.5f, new ConfigDescription("Minimum horizontal distance before a new road point is stored.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>())), config.Bind<float>("Survey", "MaximumStrokeGapMeters", 8f, new ConfigDescription("A larger gap starts a new stroke instead of drawing a long connector.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 100f), Array.Empty<object>())), config.Bind<float>("Survey", "DuplicateSuppressionMeters", 2f, new ConfigDescription("Skip samples within this distance of already-recorded road ink of the same kind, so re-walking a road never grows the atlas. 0 disables suppression; values above ~3 may also suppress tight hairpin switchbacks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())), config.Bind<float>("Persistence", "AutosaveIntervalSeconds", 15f, new ConfigDescription("Seconds between dirty-atlas autosaves.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f), Array.Empty<object>())), config.Bind<float>("Detection", "PaintThreshold", 0.4f, new ConfigDescription("Minimum averaged red/blue paint value used to identify roads.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 0.95f), Array.Empty<object>())), config.Bind<int>("Detection", "PaintSampleRadius", 1, new ConfigDescription("Terrain paint pixels sampled around the player (0 is a single pixel).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3), Array.Empty<object>())), config.Bind<int>("Map", "LineWidthPixels", 1, new ConfigDescription("Road line width on the map overlay, in map texels. One texel covers ~11.6 m of world, so widths above 1 make nearby roads merge into blobs.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 6), Array.Empty<object>())), config.Bind<bool>("Diagnostics", "DebugLogging", false, "Write diagnostic road classification messages."), config.Bind<bool>("Diagnostics", "DrawCalibrationMarkers", false, "Draw fixed calibration crosses into the dirt overlay at world origin (magenta), +128m east (yellow), and +128m north (cyan) to verify overlay/map alignment."), config.Bind<KeyCode>("Workbench", "WorkbenchHotkey", (KeyCode)112, "Key that opens the Pin Workbench for the pin under the cursor while the large map is open."), config.Bind<KeyCode>("Drawer", "DrawerHotkey", (KeyCode)108, "Key that toggles the Atlas Drawer (layers, search, saved views) while the large map is open."), config.Bind<bool>("Drawer", "ShowDirtRoads", true, "Show the dirt-road layer."), config.Bind<bool>("Drawer", "ShowPavedRoads", true, "Show the paved-road layer."), config.Bind<bool>("Drawer", "ShowPins", true, "Show managed pins on the map."), config.Bind<bool>("Drawer", "Clustering", true, "Fold crowded pins into cluster markers when zoomed out (display only; never changes stored pins)."), config.Bind<string>("Drawer", "PanelPosition", "", "Internal: the Atlas drawer's last dragged position as \"x,y\" canvas offsets from its right-center anchor. Written when the drawer closes; empty uses the default dock. Restored positions are clamped on-screen, so editing this can never strand the panel."), config.Bind<KeyCode>("Workbench", "QuickPinHotkey", (KeyCode)288, "Key that pins the object you are looking at (set to None to disable). Never pins creatures."), config.Bind<float>("Workbench", "QuickPinDuplicateRadius", 25f, new ConfigDescription("Skip a quick pin when a same-named pin already exists within this many meters (0 disables the check).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>())), config.Bind<bool>("Survey", "SurveyRulesEnabled", false, "Opt-in survey rules: nearby loaded objects matching survey-rules.tsv become reviewable observations (never pins directly)."), config.Bind<float>("Survey", "SurveyScanIntervalSeconds", 10f, new ConfigDescription("Legacy, no effect since v1.0 RC10: the survey scans continuously on a bounded per-frame budget. Kept so existing config files load cleanly.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 60f), Array.Empty<object>())), config.Bind<float>("Survey", "SurveyScanRadius", 40f, new ConfigDescription("Survey scan radius around the player in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 100f), Array.Empty<object>())), config.Bind<float>("Survey", "SurveyBaseExclusionRadius", 30f, new ConfigDescription("No observations within this distance of a pin categorized/tagged Base (0 disables).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())), config.Bind<int>("Survey", "SurveyMaxObservations", 200, new ConfigDescription("Hard cap on pending survey observations.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 1000), Array.Empty<object>())), config.Bind<KeyCode>("Routes", "RouteDrawModifier", (KeyCode)304, "Modifier held with LeftClick on the large map for route draw/erase/waypoint modes (avoids vanilla map-drag conflicts)."), config.Bind<float>("Routes", "RouteEraseRadius", 8f, new ConfigDescription("Route erase brush radius in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>())), config.Bind<float>("Routes", "RouteSnapRadius", 15f, new ConfigDescription("Waypoints snap to roads within this many meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 50f), Array.Empty<object>())), config.Bind<float>("Routes", "RouteOnRoadTolerance", 6f, new ConfigDescription("A route counts as on-road when within this distance of recorded road ink.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 15f), Array.Empty<object>())), config.Bind<float>("Routes", "RouteOffRoadSpeed", 2.5f, new ConfigDescription("Off-road travel speed (m/s) for time estimates.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 15f), Array.Empty<object>())), config.Bind<float>("Routes", "RouteOnRoadSpeed", 5f, new ConfigDescription("On-road travel speed (m/s) for time estimates.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 15f), Array.Empty<object>())), config.Bind<float>("Accessibility", "UiScale", 1f, new ConfigDescription("Scale multiplier for Concerned Cartographer panels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.8f, 1.6f), Array.Empty<object>())), config.Bind<bool>("Accessibility", "HighContrast", false, "High-contrast map ink: near-black dirt, near-white paved, brighter route colors. Kinds stay distinguishable without color (dashed/dotted styles, icons, labels)."), config.Bind<string>("Accessibility", "WorkbenchGamepadButton", "", "ZInput button name that opens the Pin Workbench (e.g. JoyLStick). Empty disables; conflicts are avoided by explicit opt-in."), config.Bind<string>("Accessibility", "DrawerGamepadButton", "", "ZInput button name that toggles the Atlas Drawer. Empty disables."), config.Bind<bool>("Pins", "EnhancedPinPalette", true, "Show the Concerned Cartographer marker palette on the large map. Markers created through it are managed from birth (no upgrade step)."), config.Bind<bool>("Pins", "ShowVanillaPinPalette", false, "Keep Valheim's own five pin-icon buttons visible alongside (or instead of) the enhanced palette. Automatically treated as true when a known conflicting pin manager is installed."), config.Bind<CrashConsentState>("Privacy", "SendCrashReports", CrashConsentState.Unknown, "Send anonymous crash reports when Concerned Cartographer hits an internal error. Unknown = not asked yet (a one-time dialog appears on the first large-map open); nothing is ever sent while Unknown or Disabled. What is and is not collected: PRIVACY.md. No gameplay analytics, ever."), config.Bind<int>("Privacy", "AcceptedPrivacyPolicyVersion", 0, "Internal: the crash-reporting policy version the player answered. Re-prompts only if the collected data categories materially change in a future release."), config.Bind<string>("Privacy", "SentryDsn", "", "Advanced: override the embedded crash-report ingestion DSN (a public event-submission key). Empty uses the built-in value; if both are empty, crash reporting is fully inert. NEVER put a Sentry auth token here."), config.Bind<bool>("Map", "ShowVanillaMapControls", false, "Show Valheim's own right-side map control rail (pin icon selectors, death/boss filter buttons, visible-to-others toggle) alongside the Concerned Cartographer toolbar. Default: the CC toolbar and Atlas System Markers replace it. Automatically treated as true when a known conflicting pin manager is installed."), config.Bind<bool>("Map", "HighPrecisionLargeMapRoads", true, "Render roads on the LARGE map as sub-texel vector geometry that pans/zooms with the map (DEF-v1.0-006), instead of only the 2048-texel texture overlay (which stays for the minimap and as fallback)