Decompiled source of GridLock v1.2.0

GridLock.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using AskaGridLock.Core;
using AskaGridLock.Core.Laser;
using AskaShared.Game;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Fusion;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using SSSGame;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("GridLock")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.0")]
[assembly: AssemblyInformationalVersion("1.2.0+aa1799960f1d860b1881778c3d714bbfa35d0471")]
[assembly: AssemblyProduct("Grid Lock")]
[assembly: AssemblyTitle("GridLock")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AskaGridLock
{
	[HarmonyPatch(typeof(Character))]
	public static class CharacterSpawnPatch
	{
		internal static Character LocalCharacter => LocalPlayerTool.LocalCharacter;

		[HarmonyPostfix]
		[HarmonyPatch("Spawned")]
		public static void Spawned(Character __instance)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			LocalPlayerTool.AttachOnSpawn(__instance, Plugin.Log, "GridLockTool", Vector3.zero, typeof(GridLockTool));
			LocalPlayerTool.AttachOnSpawn(__instance, Plugin.Log, "GridLockLaser", Vector3.zero, typeof(LaserOverlay));
		}
	}
	internal static class GridLockConfig
	{
		private static ConfigEntry<bool> _enabled;

		private static ConfigEntry<bool> _snapTerrain;

		private static ConfigEntry<bool> _snapSkewed;

		private static ConfigEntry<double> _spacing;

		private static ConfigEntry<double> _rotationStep;

		private static ConfigEntry<double> _postSnapRadius;

		private static ConfigEntry<bool> _laserEnabled;

		private static ConfigEntry<double> _laserExtensionLength;

		private static ConfigEntry<double> _alignmentDetectionDistance;

		private static ConfigEntry<double> _alignmentTolerance;

		private static ConfigEntry<double> _laserVisualThickness;

		private static ConfigEntry<double> _laserGlowIntensity;

		private static ConfigEntry<double> _snapIndicatorSize;

		private static ConfigEntry<double> _laserHeightLimit;

		private static ConfigEntry<double> _snapIndicatorRadius;

		private static ConfigEntry<double> _minFootprintHalfExtent;

		private static ConfigEntry<bool> _alignmentSnap;

		private static ConfigEntry<double> _alignmentSnapCapture;

		private static ConfigEntry<double> _laserHaloScale;

		private static ConfigEntry<bool> _laserPulse;

		private static ConfigEntry<double> _snapIndicatorThickness;

		private const double SquareSize = 2.0;

		internal static ConfigEntry<KeyCode> FreeMoveKey;

		internal static bool Enabled
		{
			get
			{
				if (_enabled != null)
				{
					return _enabled.Value;
				}
				return false;
			}
		}

		internal static bool SnapTerrain
		{
			get
			{
				if (_snapTerrain != null)
				{
					return _snapTerrain.Value;
				}
				return false;
			}
		}

		internal static bool SnapSkewed
		{
			get
			{
				if (_snapSkewed != null)
				{
					return _snapSkewed.Value;
				}
				return true;
			}
		}

		internal static GridConfig Grid { get; private set; }

		internal static bool LaserEnabled
		{
			get
			{
				if (Enabled && _laserEnabled != null)
				{
					return _laserEnabled.Value;
				}
				return false;
			}
		}

		internal static LaserConfig Laser { get; private set; }

		internal static bool AlignmentSnapEnabled
		{
			get
			{
				if (_alignmentSnap != null)
				{
					return _alignmentSnap.Value;
				}
				return true;
			}
		}

		internal static bool LaserPulseEnabled
		{
			get
			{
				if (_laserPulse != null)
				{
					return _laserPulse.Value;
				}
				return false;
			}
		}

		internal static void Init(ConfigFile config)
		{
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Expected O, but got Unknown
			//IL_0389: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Expected O, but got Unknown
			//IL_04bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Expected O, but got Unknown
			//IL_04e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e8: Expected O, but got Unknown
			//IL_054c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0552: Expected O, but got Unknown
			//IL_05b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bc: Expected O, but got Unknown
			//IL_0620: Unknown result type (might be due to invalid IL or missing references)
			//IL_0626: Expected O, but got Unknown
			//IL_068a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0690: Expected O, but got Unknown
			//IL_06f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_06fa: Expected O, but got Unknown
			//IL_075e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0764: Expected O, but got Unknown
			//IL_07c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ce: Expected O, but got Unknown
			//IL_0832: Unknown result type (might be due to invalid IL or missing references)
			//IL_0838: Expected O, but got Unknown
			//IL_089c: Unknown result type (might be due to invalid IL or missing references)
			//IL_08a2: Expected O, but got Unknown
			//IL_0906: Unknown result type (might be due to invalid IL or missing references)
			//IL_090c: Expected O, but got Unknown
			//IL_0970: Unknown result type (might be due to invalid IL or missing references)
			//IL_0976: Expected O, but got Unknown
			_enabled = config.Bind<bool>("Grid", "Enabled", true, "Master switch. When false the mod snaps nothing.");
			_snapTerrain = config.Bind<bool>("Grid", "SnapTerrain", true, "Snap the Terrain Level Field tool's start point to the grid so leveled areas align with placed structures.");
			_snapSkewed = config.Bind<bool>("Grid", "SnapSkewed", true, "Snap fences, gates, and hedges (the Skewed placement family) like a normal structure: grid position, rotation, Shift free-move, and post-to-post join onto an existing pole. Set false to leave them fully vanilla.");
			_spacing = config.Bind<double>("Grid", "Spacing", 0.5, "Minimum snap increment, in terraforming squares. One square is 2 world units, so the world snap step is Spacing * 2 (default 0.5 = 1.0 units).");
			_rotationStep = config.Bind<double>("Grid", "RotationStep", 15.0, "Rotation snap increment in degrees.");
			_postSnapRadius = config.Bind<double>("Grid", "PostSnapRadius", 1.0, "World-unit distance within which a fence/gate/hedge pole snaps onto an already-placed pole (post-to-post join); it is also the distance at which the join releases as you move away. 0 disables post-snap. Clamped to 0..3.");
			_laserEnabled = config.Bind<bool>("Laser", "Enabled", true, "Draw the alignment laser overlay while a build ghost is live. The [Grid] Enabled master switch gates it as well.");
			_laserExtensionLength = config.Bind<double>("Laser", "LaserExtensionLength", 10.0, "How far each footprint edge's laser reaches past the structure, in world units. Clamped to 0.5..20.");
			_alignmentDetectionDistance = config.Bind<double>("Laser", "AlignmentDetectionDistance", 20.0, "Radius around the ghost, in world units, within which already-placed structures contribute alignment guides. Clamped to 1..50.");
			_alignmentTolerance = config.Bind<double>("Laser", "AlignmentTolerance", 0.05, "Largest perpendicular gap between two edge lines that still counts as aligned, in world units. Clamped to 0.001..0.5.");
			_laserVisualThickness = config.Bind<double>("Laser", "LaserVisualThickness", 0.05, "Laser line width in world units. Clamped to 0.005..0.5.");
			_laserGlowIntensity = config.Bind<double>("Laser", "LaserGlowIntensity", 1.5, "Sets the halo strength: halo alpha is 0.25 times this value, clamped to 0.05..1. Does not affect the laser's core line. Clamped to 0.1..5.");
			_snapIndicatorSize = config.Bind<double>("Laser", "SnapIndicatorSize", 0.08, "Total length of each cross segment of a red snap-point indicator, in world units. Clamped to 0.01..0.5.");
			_laserHeightLimit = config.Bind<double>("Laser", "LaserHeightLimit", 3.0, "Highest a draped line may float above the ground it follows, in world units. A ghost hovering further above the terrain than this keeps its lines on the ground rather than in the air with it. Clamped to 0.25..20.");
			_snapIndicatorRadius = config.Bind<double>("Laser", "SnapIndicatorRadius", 15.0, "Half-width, in world units, of the square of red snap crosses drawn around the ghost. 15 covers a 31x31 square of intersections on the default 1-unit grid. Clamped to 1..50.");
			_minFootprintHalfExtent = config.Bind<double>("Laser", "MinFootprintHalfExtent", 0.75, "Smallest footprint half extent, in world units, that still draws guides. A placed structure below this on both axes - a flag, marker, or small prop - contributes nothing. 0 excludes nothing. Clamped to 0..5.");
			_alignmentSnap = config.Bind<bool>("Laser", "AlignmentSnap", true, "Pull an angled build ghost onto a parallel guide of an already-placed structure, so a row of rotated structures can share a wall line the square grid cannot land on. Never applies to a cardinal (0/90/180/270) ghost, to fences, gates, and hedges, or while the free-move key is held.");
			_alignmentSnapCapture = config.Bind<double>("Laser", "AlignmentSnapCapture", 0.5, "Largest perpendicular gap, in world units, at which a ghost edge is pulled onto a parallel guide; it is also the distance at which the pull releases as you move away. Clamped to 0.05..2.");
			_laserHaloScale = config.Bind<double>("Laser", "LaserHaloScale", 4.0, "Width of the soft halo drawn under each laser, as a multiple of LaserVisualThickness. Unitless, so 4 draws a halo four times as wide as the line inside it. 0 draws the line on its own. Clamped to 0..10.");
			_laserPulse = config.Bind<bool>("Laser", "LaserPulse", false, "Pulse the brightness of every laser's inner line by 8%, one cycle per second. Off by default; the halo and the snap crosses never pulse.");
			_snapIndicatorThickness = config.Bind<double>("Laser", "SnapIndicatorThickness", 0.02, "Line width of the red snap crosses, in world units, independent of LaserVisualThickness. Clamped to 0.005..0.2.");
			FreeMoveKey = config.Bind<KeyCode>("Grid", "FreeMoveKey", (KeyCode)304, "Hold to move the ghost freely off the grid, preserving its current rotation. Release to re-snap to the nearest grid pose.");
			GridConfig grid = default(GridConfig);
			((GridConfig)(ref grid))..ctor(_spacing.Value, _rotationStep.Value, 2.0, _postSnapRadius.Value);
			Grid = grid;
			bool flag = default(bool);
			if (((GridConfig)(ref grid)).Spacing != _spacing.Value)
			{
				ManualLogSource log = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(32, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] Spacing ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_spacing.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((GridConfig)(ref grid)).Spacing);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log.LogInfo(val);
			}
			if (((GridConfig)(ref grid)).RotationStep != _rotationStep.Value)
			{
				ManualLogSource log2 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(37, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] RotationStep ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_rotationStep.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((GridConfig)(ref grid)).RotationStep);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log2.LogInfo(val);
			}
			if (((GridConfig)(ref grid)).PostSnapRadius != _postSnapRadius.Value)
			{
				ManualLogSource log3 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(39, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] PostSnapRadius ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_postSnapRadius.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((GridConfig)(ref grid)).PostSnapRadius);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log3.LogInfo(val);
			}
			LaserConfig laser = default(LaserConfig);
			((LaserConfig)(ref laser))..ctor(_laserExtensionLength.Value, _alignmentDetectionDistance.Value, _alignmentTolerance.Value, _laserVisualThickness.Value, _laserGlowIntensity.Value, _snapIndicatorSize.Value, _laserHeightLimit.Value, _snapIndicatorRadius.Value, _minFootprintHalfExtent.Value, _alignmentSnapCapture.Value, _laserHaloScale.Value, _snapIndicatorThickness.Value);
			Laser = laser;
			if (((LaserConfig)(ref laser)).ExtensionLength != _laserExtensionLength.Value)
			{
				ManualLogSource log4 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(45, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] LaserExtensionLength ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_laserExtensionLength.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((LaserConfig)(ref laser)).ExtensionLength);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log4.LogInfo(val);
			}
			if (((LaserConfig)(ref laser)).DetectionDistance != _alignmentDetectionDistance.Value)
			{
				ManualLogSource log5 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(51, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] AlignmentDetectionDistance ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_alignmentDetectionDistance.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((LaserConfig)(ref laser)).DetectionDistance);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log5.LogInfo(val);
			}
			if (((LaserConfig)(ref laser)).Tolerance != _alignmentTolerance.Value)
			{
				ManualLogSource log6 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(43, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] AlignmentTolerance ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_alignmentTolerance.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((LaserConfig)(ref laser)).Tolerance);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log6.LogInfo(val);
			}
			if (((LaserConfig)(ref laser)).Thickness != _laserVisualThickness.Value)
			{
				ManualLogSource log7 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(45, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] LaserVisualThickness ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_laserVisualThickness.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((LaserConfig)(ref laser)).Thickness);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log7.LogInfo(val);
			}
			if (((LaserConfig)(ref laser)).GlowIntensity != _laserGlowIntensity.Value)
			{
				ManualLogSource log8 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(43, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] LaserGlowIntensity ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_laserGlowIntensity.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((LaserConfig)(ref laser)).GlowIntensity);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log8.LogInfo(val);
			}
			if (((LaserConfig)(ref laser)).SnapIndicatorSize != _snapIndicatorSize.Value)
			{
				ManualLogSource log9 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(42, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] SnapIndicatorSize ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_snapIndicatorSize.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((LaserConfig)(ref laser)).SnapIndicatorSize);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log9.LogInfo(val);
			}
			if (((LaserConfig)(ref laser)).HeightLimit != _laserHeightLimit.Value)
			{
				ManualLogSource log10 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(41, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] LaserHeightLimit ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_laserHeightLimit.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((LaserConfig)(ref laser)).HeightLimit);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log10.LogInfo(val);
			}
			if (((LaserConfig)(ref laser)).SnapIndicatorRadius != _snapIndicatorRadius.Value)
			{
				ManualLogSource log11 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(44, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] SnapIndicatorRadius ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_snapIndicatorRadius.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((LaserConfig)(ref laser)).SnapIndicatorRadius);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log11.LogInfo(val);
			}
			if (((LaserConfig)(ref laser)).MinFootprintHalfExtent != _minFootprintHalfExtent.Value)
			{
				ManualLogSource log12 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(47, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] MinFootprintHalfExtent ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_minFootprintHalfExtent.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((LaserConfig)(ref laser)).MinFootprintHalfExtent);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log12.LogInfo(val);
			}
			if (((LaserConfig)(ref laser)).SnapCapture != _alignmentSnapCapture.Value)
			{
				ManualLogSource log13 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(45, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] AlignmentSnapCapture ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_alignmentSnapCapture.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((LaserConfig)(ref laser)).SnapCapture);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log13.LogInfo(val);
			}
			if (((LaserConfig)(ref laser)).HaloScale != _laserHaloScale.Value)
			{
				ManualLogSource log14 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(39, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] LaserHaloScale ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_laserHaloScale.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((LaserConfig)(ref laser)).HaloScale);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log14.LogInfo(val);
			}
			if (((LaserConfig)(ref laser)).SnapIndicatorThickness != _snapIndicatorThickness.Value)
			{
				ManualLogSource log15 = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(47, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock] SnapIndicatorThickness ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(_snapIndicatorThickness.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" clamped to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<double>(((LaserConfig)(ref laser)).SnapIndicatorThickness);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log15.LogInfo(val);
			}
		}
	}
	public class GridLockTool : MonoBehaviour
	{
		private void Update()
		{
			SnapPatches.TickFreeMode();
		}
	}
	internal static class AlignmentSnapState
	{
		private static readonly List<LaserLine[]> Lines = new List<LaserLine[]>();

		private static bool _hasMoving;

		private static double _offsetX;

		private static double _offsetZ;

		private static double _halfX;

		private static double _halfZ;

		internal static IReadOnlyList<LaserLine[]> StationaryLines => Lines;

		internal static void Publish(in WorldFootprint moving, List<LaserLine[]> stationaryLines)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			Lines.Clear();
			if (stationaryLines != null)
			{
				for (int i = 0; i < stationaryLines.Count; i++)
				{
					Lines.Add(stationaryLines[i]);
				}
			}
			Footprint2D footprint = moving.Footprint;
			if (!((Footprint2D)(ref footprint)).IsValid)
			{
				_hasMoving = false;
				return;
			}
			double num = ((Footprint2D)(ref footprint)).CenterX - (double)moving.PivotX;
			double num2 = ((Footprint2D)(ref footprint)).CenterZ - (double)moving.PivotZ;
			(double, double) tuple = Footprint2D.Right(((Footprint2D)(ref footprint)).YawDegrees);
			(double, double) tuple2 = Footprint2D.Forward(((Footprint2D)(ref footprint)).YawDegrees);
			_offsetX = num * tuple.Item1 + num2 * tuple.Item2;
			_offsetZ = num * tuple2.Item1 + num2 * tuple2.Item2;
			_halfX = ((Footprint2D)(ref footprint)).HalfX;
			_halfZ = ((Footprint2D)(ref footprint)).HalfZ;
			_hasMoving = true;
		}

		internal static void Clear()
		{
			Lines.Clear();
			_hasMoving = false;
			_offsetX = 0.0;
			_offsetZ = 0.0;
			_halfX = 0.0;
			_halfZ = 0.0;
		}

		internal static bool TryGetMovingLocal(out double offX, out double offZ, out double halfX, out double halfZ)
		{
			offX = (_hasMoving ? _offsetX : 0.0);
			offZ = (_hasMoving ? _offsetZ : 0.0);
			halfX = (_hasMoving ? _halfX : 0.0);
			halfZ = (_hasMoving ? _halfZ : 0.0);
			return _hasMoving;
		}
	}
	internal static class FootprintReader
	{
		private static bool _failureLogged;

		private static bool _footprintComponentFailureLogged;

		internal static bool TryRead(GameObject root, out WorldFootprint result)
		{
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			result = default(WorldFootprint);
			try
			{
				if ((Object)(object)root == (Object)null)
				{
					return false;
				}
				Transform transform = root.transform;
				Vector3 position = transform.position;
				double num = transform.eulerAngles.y;
				double num2 = (0.0 - num) * Math.PI / 180.0;
				double cos = Math.Cos(num2);
				double sin = Math.Sin(num2);
				double minX = double.MaxValue;
				double maxX = double.MinValue;
				double minZ = double.MaxValue;
				double maxZ = double.MinValue;
				float minY = float.MaxValue;
				float maxY = float.MinValue;
				bool flag = false;
				BoxCollider val = TryFindFootprintCollider(root);
				if ((Object)(object)val != (Object)null)
				{
					BoxLocalBounds(val, out var lo, out var hi);
					Accumulate(lo, hi, ((Component)val).transform, position, cos, sin, ref minX, ref maxX, ref minZ, ref maxZ, ref minY, ref maxY);
					flag = true;
				}
				if (!flag)
				{
					List<BoxCollider> list = CollectLogicFootprintBoxes(root);
					for (int i = 0; i < list.Count; i++)
					{
						BoxCollider val2 = list[i];
						BoxLocalBounds(val2, out var lo2, out var hi2);
						Accumulate(lo2, hi2, ((Component)val2).transform, position, cos, sin, ref minX, ref maxX, ref minZ, ref maxZ, ref minY, ref maxY);
						flag = true;
					}
				}
				string reason;
				if (!flag)
				{
					Il2CppArrayBase<Collider> componentsInChildren = root.GetComponentsInChildren<Collider>(true);
					int num3 = componentsInChildren?.Length ?? 0;
					for (int j = 0; j < num3; j++)
					{
						Collider val3 = componentsInChildren[j];
						if (!((Object)(object)val3 == (Object)null) && !ShouldSkipCollider(val3, out reason) && TryLocalBox(val3, out var lo3, out var hi3))
						{
							Accumulate(lo3, hi3, ((Component)val3).transform, position, cos, sin, ref minX, ref maxX, ref minZ, ref maxZ, ref minY, ref maxY);
							flag = true;
						}
					}
				}
				if (!flag)
				{
					Il2CppArrayBase<Renderer> componentsInChildren2 = root.GetComponentsInChildren<Renderer>(true);
					int num4 = componentsInChildren2?.Length ?? 0;
					for (int k = 0; k < num4; k++)
					{
						Renderer val4 = componentsInChildren2[k];
						if (!((Object)(object)val4 == (Object)null) && TryRendererLocalBox(val4, out var lo4, out var hi4, out reason))
						{
							Accumulate(lo4, hi4, ((Component)val4).transform, position, cos, sin, ref minX, ref maxX, ref minZ, ref maxZ, ref minY, ref maxY);
							flag = true;
						}
					}
				}
				if (!flag)
				{
					return false;
				}
				double num5 = (minX + maxX) * 0.5;
				double num6 = (minZ + maxZ) * 0.5;
				double num7 = num * Math.PI / 180.0;
				double num8 = Math.Cos(num7);
				double num9 = Math.Sin(num7);
				double num10 = (double)position.x + (num5 * num8 + num6 * num9);
				double num11 = (double)position.z + ((0.0 - num5) * num9 + num6 * num8);
				Footprint2D footprint = default(Footprint2D);
				((Footprint2D)(ref footprint))..ctor(num10, num11, num, (maxX - minX) * 0.5, (maxZ - minZ) * 0.5);
				if (!((Footprint2D)(ref footprint)).IsValid)
				{
					return false;
				}
				result = new WorldFootprint(footprint, minY, maxY, position.x, position.z);
				return true;
			}
			catch (Exception ex)
			{
				if (!_failureLogged)
				{
					_failureLogged = true;
					ManualLogSource log = Plugin.Log;
					bool flag2 = default(bool);
					BepInExErrorLogInterpolatedStringHandler val5 = new BepInExErrorLogInterpolatedStringHandler(74, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("[GridLock][laser] FootprintReader.TryRead threw (logged once, fail-open): ");
						((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<Exception>(ex);
					}
					log.LogError(val5);
				}
				return false;
			}
		}

		private static BoxCollider TryFindFootprintCollider(GameObject root)
		{
			try
			{
				StructureFootprint componentInChildren = root.GetComponentInChildren<StructureFootprint>(true);
				if ((Object)(object)componentInChildren == (Object)null)
				{
					return null;
				}
				BoxCollider footprintCollider = componentInChildren.FootprintCollider;
				if ((Object)(object)footprintCollider != (Object)null)
				{
					return footprintCollider;
				}
				GameObject footprint = componentInChildren.footprint;
				return ((Object)(object)footprint != (Object)null) ? footprint.GetComponent<BoxCollider>() : null;
			}
			catch (Exception value)
			{
				if (!_footprintComponentFailureLogged)
				{
					_footprintComponentFailureLogged = true;
					Plugin.Log.LogWarning((object)("[GridLock][laser] StructureFootprint lookup threw (logged once, fail-open " + $"to the collider scan): {value}"));
				}
				return null;
			}
		}

		private static List<BoxCollider> CollectLogicFootprintBoxes(GameObject root)
		{
			List<BoxCollider> list = new List<BoxCollider>();
			Il2CppArrayBase<Collider> componentsInChildren = root.GetComponentsInChildren<Collider>(true);
			int num = componentsInChildren?.Length ?? 0;
			for (int i = 0; i < num; i++)
			{
				Collider val = componentsInChildren[i];
				if (!((Object)(object)val == (Object)null))
				{
					BoxCollider val2 = ((Il2CppObjectBase)val).TryCast<BoxCollider>();
					if (!((Object)(object)val2 == (Object)null) && IsLogicFootprintBox(val2))
					{
						list.Add(val2);
					}
				}
			}
			return list;
		}

		private static bool IsLogicFootprintBox(BoxCollider box)
		{
			Transform transform = ((Component)box).transform;
			if (!string.Equals(((Object)((Component)transform).gameObject).name, "Footprint", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			Transform parent = transform.parent;
			if ((Object)(object)parent != (Object)null)
			{
				return string.Equals(((Object)((Component)parent).gameObject).name, "Logic", StringComparison.OrdinalIgnoreCase);
			}
			return false;
		}

		private static void BoxLocalBounds(BoxCollider box, out Vector3 lo, out Vector3 hi)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = box.size * 0.5f;
			lo = box.center - val;
			hi = box.center + val;
		}

		private static bool TryLocalBox(Collider c, out Vector3 lo, out Vector3 hi)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			lo = default(Vector3);
			hi = default(Vector3);
			BoxCollider val = ((Il2CppObjectBase)c).TryCast<BoxCollider>();
			if ((Object)(object)val != (Object)null)
			{
				BoxLocalBounds(val, out lo, out hi);
				return true;
			}
			MeshCollider val2 = ((Il2CppObjectBase)c).TryCast<MeshCollider>();
			if ((Object)(object)val2 != (Object)null)
			{
				Mesh sharedMesh = val2.sharedMesh;
				if ((Object)(object)sharedMesh == (Object)null)
				{
					return false;
				}
				Bounds bounds = sharedMesh.bounds;
				lo = ((Bounds)(ref bounds)).min;
				hi = ((Bounds)(ref bounds)).max;
				return true;
			}
			SphereCollider val3 = ((Il2CppObjectBase)c).TryCast<SphereCollider>();
			if ((Object)(object)val3 != (Object)null)
			{
				float radius = val3.radius;
				Vector3 val4 = default(Vector3);
				((Vector3)(ref val4))..ctor(radius, radius, radius);
				lo = val3.center - val4;
				hi = val3.center + val4;
				return true;
			}
			CapsuleCollider val5 = ((Il2CppObjectBase)c).TryCast<CapsuleCollider>();
			if ((Object)(object)val5 != (Object)null)
			{
				float radius2 = val5.radius;
				float num = Mathf.Max(val5.height * 0.5f, radius2);
				Vector3 val6 = default(Vector3);
				((Vector3)(ref val6))..ctor((val5.direction == 0) ? num : radius2, (val5.direction == 1) ? num : radius2, (val5.direction == 2) ? num : radius2);
				lo = val5.center - val6;
				hi = val5.center + val6;
				return true;
			}
			return false;
		}

		private static bool ShouldSkipCollider(Collider c, out string reason)
		{
			if (!c.enabled)
			{
				reason = "disabled";
				return true;
			}
			if (c.isTrigger && !IsFootprintNamed(((Object)c).name))
			{
				reason = "trigger not footprint-named";
				return true;
			}
			reason = null;
			return false;
		}

		private static bool TryRendererLocalBox(Renderer r, out Vector3 lo, out Vector3 hi, out string skipReason)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			lo = default(Vector3);
			hi = default(Vector3);
			if (!r.enabled)
			{
				skipReason = "disabled";
				return false;
			}
			MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
			if ((Object)(object)component == (Object)null)
			{
				skipReason = "no MeshFilter";
				return false;
			}
			Mesh sharedMesh = component.sharedMesh;
			if ((Object)(object)sharedMesh == (Object)null)
			{
				skipReason = "no sharedMesh";
				return false;
			}
			Bounds bounds = sharedMesh.bounds;
			lo = ((Bounds)(ref bounds)).min;
			hi = ((Bounds)(ref bounds)).max;
			skipReason = null;
			return true;
		}

		private static void Accumulate(Vector3 lo, Vector3 hi, Transform contributor, Vector3 origin, double cos, double sin, ref double minX, ref double maxX, ref double minZ, ref double maxZ, ref float minY, ref float maxY)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			for (int i = 0; i < 8; i++)
			{
				((Vector3)(ref val))..ctor(((i & 1) == 0) ? lo.x : hi.x, ((i & 2) == 0) ? lo.y : hi.y, ((i & 4) == 0) ? lo.z : hi.z);
				Vector3 val2 = contributor.TransformPoint(val);
				double num = val2.x - origin.x;
				double num2 = val2.z - origin.z;
				double num3 = num * cos + num2 * sin;
				double num4 = (0.0 - num) * sin + num2 * cos;
				if (num3 < minX)
				{
					minX = num3;
				}
				if (num3 > maxX)
				{
					maxX = num3;
				}
				if (num4 < minZ)
				{
					minZ = num4;
				}
				if (num4 > maxZ)
				{
					maxZ = num4;
				}
				if (val2.y < minY)
				{
					minY = val2.y;
				}
				if (val2.y > maxY)
				{
					maxY = val2.y;
				}
			}
		}

		private static bool IsFootprintNamed(string name)
		{
			if (name != null)
			{
				return name.IndexOf("footprint", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}
	}
	internal sealed class LaserLinePool
	{
		private const float MinSqrLength = 1E-08f;

		private const float MinWidth = 0.001f;

		private const float MinAlpha = 0.001f;

		private readonly List<LineRenderer> _pool = new List<LineRenderer>(64);

		private readonly Transform _root;

		private readonly int _sortingOrder;

		private readonly LineTextureMode _textureMode;

		private readonly Material _material;

		private int _used;

		private bool _failureLogged;

		internal int LineCount => _used;

		internal LaserLinePool(Transform parent, string name, int sortingOrder)
			: this(parent, name, sortingOrder, null, (LineTextureMode)0)
		{
		}

		internal LaserLinePool(Transform parent, string name, int sortingOrder, Material material, LineTextureMode textureMode)
		{
			//IL_0023: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			_sortingOrder = sortingOrder;
			_material = material;
			_textureMode = textureMode;
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			_root = val.transform;
		}

		internal void BeginFrame()
		{
			try
			{
				int num = Math.Min(_used, _pool.Count);
				for (int i = 0; i < num; i++)
				{
					LineRenderer val = _pool[i];
					if ((Object)(object)val != (Object)null)
					{
						((Renderer)val).enabled = false;
					}
				}
			}
			catch (Exception ex)
			{
				LogOnce("BeginFrame", ex);
			}
			_used = 0;
		}

		internal void AddLine(Vector3 a, Vector3 b, Color color, float width)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if (width < 0.001f || color.a < 0.001f)
			{
				return;
			}
			Vector3 val = a - b;
			if (((Vector3)(ref val)).sqrMagnitude < 1E-08f)
			{
				return;
			}
			try
			{
				LineRenderer val2 = Rent(_used);
				if (!((Object)(object)val2 == (Object)null))
				{
					_used++;
					((Renderer)val2).enabled = true;
					val2.positionCount = 2;
					val2.SetPosition(0, a);
					val2.SetPosition(1, b);
					Style(val2, color, width);
				}
			}
			catch (Exception ex)
			{
				LogOnce("AddLine", ex);
			}
		}

		internal void AddLine(List<Vector3> points, Color color, float width)
		{
			//IL_0015: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			if (points == null || points.Count < 2 || width < 0.001f || color.a < 0.001f)
			{
				return;
			}
			Vector3 val = points[0];
			bool flag = false;
			for (int i = 1; i < points.Count; i++)
			{
				Vector3 val2 = points[i] - val;
				if (((Vector3)(ref val2)).sqrMagnitude >= 1E-08f)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				return;
			}
			try
			{
				LineRenderer val3 = Rent(_used);
				if (!((Object)(object)val3 == (Object)null))
				{
					_used++;
					((Renderer)val3).enabled = true;
					val3.positionCount = points.Count;
					for (int j = 0; j < points.Count; j++)
					{
						val3.SetPosition(j, points[j]);
					}
					Style(val3, color, width);
				}
			}
			catch (Exception ex)
			{
				LogOnce("AddLine", ex);
			}
		}

		private void Style(LineRenderer line, Color color, float width)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			line.loop = false;
			line.startWidth = width;
			line.endWidth = width;
			line.widthMultiplier = 1f;
			line.startColor = color;
			line.endColor = color;
			Material val = (((Object)(object)_material != (Object)null) ? _material : LaserMaterial.Get());
			if ((Object)(object)val != (Object)null)
			{
				((Renderer)line).material = val;
			}
		}

		private LineRenderer Rent(int index)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			while (_pool.Count <= index)
			{
				GameObject val = new GameObject($"Line_{_pool.Count}");
				val.transform.SetParent(_root, false);
				LineRenderer val2 = val.AddComponent<LineRenderer>();
				val2.useWorldSpace = true;
				val2.textureMode = _textureMode;
				val2.alignment = (LineAlignment)0;
				val2.numCapVertices = 4;
				val2.numCornerVertices = 2;
				((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)val2).receiveShadows = false;
				((Renderer)val2).lightProbeUsage = (LightProbeUsage)0;
				((Renderer)val2).reflectionProbeUsage = (ReflectionProbeUsage)0;
				((Renderer)val2).motionVectorGenerationMode = (MotionVectorGenerationMode)2;
				((Renderer)val2).sortingOrder = _sortingOrder;
				((Renderer)val2).enabled = false;
				_pool.Add(val2);
			}
			return _pool[index];
		}

		private void LogOnce(string where, Exception ex)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			if (!_failureLogged)
			{
				_failureLogged = true;
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(65, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock][laser] LaserLinePool.");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(where);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" threw (logged once, fail-open): ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}
	}
	internal static class LaserMaterial
	{
		private const int HaloTextureHeight = 16;

		private const float HaloCentreAlpha = 1f;

		private static Material _material;

		private static bool _resolved;

		private static Material _halo;

		private static bool _haloResolved;

		private static Texture2D _haloTexture;

		internal static Material Get()
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (_resolved)
			{
				return _material;
			}
			_resolved = true;
			bool flag = default(bool);
			try
			{
				Shader val = Shader.Find("Sprites/Default");
				if ((Object)(object)val == (Object)null)
				{
					val = Shader.Find("Unlit/Color");
				}
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)"[GridLock][laser] no line shader found (Sprites/Default and Unlit/Color both missing); lasers draw with Unity's default material.");
					return null;
				}
				Material val2 = new Material(val);
				if (val2.HasProperty("_Color"))
				{
					val2.SetColor("_Color", Color.white);
				}
				_material = val2;
				ManualLogSource log = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(40, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[GridLock][laser] line material shader: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(((Object)val).name);
				}
				log.LogInfo(val3);
			}
			catch (Exception ex)
			{
				_material = null;
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val4 = new BepInExErrorLogInterpolatedStringHandler(69, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[GridLock][laser] line shader lookup threw (logged once, fail-open): ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<Exception>(ex);
				}
				log2.LogError(val4);
			}
			return _material;
		}

		internal static Material GetHalo()
		{
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			if (_haloResolved)
			{
				return _halo;
			}
			_haloResolved = true;
			bool flag = default(bool);
			try
			{
				Shader val = Shader.Find("Legacy Shaders/Particles/Additive");
				if ((Object)(object)val == (Object)null)
				{
					val = Shader.Find("Particles/Additive");
				}
				if ((Object)(object)val == (Object)null)
				{
					val = Shader.Find("Mobile/Particles/Additive");
				}
				if ((Object)(object)val == (Object)null)
				{
					val = Shader.Find("Sprites/Default");
				}
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)"[GridLock][laser] no halo shader found (the three additive shaders and Sprites/Default are all missing); lasers draw their core only.");
					return null;
				}
				Material val2 = new Material(val);
				if (val2.HasProperty("_Color"))
				{
					val2.SetColor("_Color", Color.white);
				}
				Texture2D val3 = BuildFalloff();
				if ((Object)(object)val3 != (Object)null)
				{
					_haloTexture = val3;
					val2.mainTexture = (Texture)(object)val3;
				}
				_halo = val2;
				ManualLogSource log = Plugin.Log;
				BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(40, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[GridLock][laser] halo material shader: ");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(((Object)val).name);
				}
				log.LogInfo(val4);
			}
			catch (Exception ex)
			{
				_halo = null;
				_haloTexture = null;
				ManualLogSource log2 = Plugin.Log;
				BepInExErrorLogInterpolatedStringHandler val5 = new BepInExErrorLogInterpolatedStringHandler(70, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("[GridLock][laser] halo material build threw (logged once, fail-open): ");
					((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<Exception>(ex);
				}
				log2.LogError(val5);
			}
			return _halo;
		}

		private static Texture2D BuildFalloff()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(1, 16, (TextureFormat)4, false);
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)1;
			for (int i = 0; i < 16; i++)
			{
				float t = Mathf.Abs((((float)i + 0.5f) / 16f - 0.5f) * 2f);
				val.SetPixel(0, i, new Color(1f, 1f, 1f, 1f * (1f - Smoothstep(t))));
			}
			val.Apply();
			return val;
		}

		private static float Smoothstep(float t)
		{
			if (t <= 0f)
			{
				return 0f;
			}
			if (t >= 1f)
			{
				return 1f;
			}
			return t * t * (3f - 2f * t);
		}
	}
	public class LaserOverlay : MonoBehaviour
	{
		private const int MaxSnapPoints = 1024;

		private const double PulseAmplitude = 0.08;

		private const float AlignedWidening = 1.3f;

		private const int StationaryHaloSortingOrder = 5000;

		private const int StationarySortingOrder = 5001;

		private const int SnapSortingOrder = 5002;

		private const int MovingHaloSortingOrder = 5003;

		private const int MovingSortingOrder = 5004;

		private const int AlignedHaloSortingOrder = 5005;

		private const int AlignedSortingOrder = 5006;

		private bool _failureLogged;

		private bool _drawFailureLogged;

		private bool _poolFailureLogged;

		private LaserLinePool _stationaryHaloPool;

		private LaserLinePool _stationaryPool;

		private LaserLinePool _snapPool;

		private LaserLinePool _movingHaloPool;

		private LaserLinePool _movingPool;

		private LaserLinePool _alignedHaloPool;

		private LaserLinePool _alignedPool;

		private readonly List<Vector3> _drapeBuffer = new List<Vector3>(64);

		private IReadOnlyList<List<Vector3>[]> _stationaryDraped;

		internal bool HasData;

		internal WorldFootprint Moving;

		internal LaserLine[] MovingLines;

		internal IReadOnlyList<WorldFootprint> Stationary;

		internal List<LaserLine[]> StationaryLines;

		internal List<AlignmentMatch> Matches;

		internal bool FreeMove;

		private void Awake()
		{
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Expected O, but got Unknown
			MovingLines = Array.Empty<LaserLine>();
			StationaryLines = new List<LaserLine[]>();
			try
			{
				Material halo = LaserMaterial.GetHalo();
				_stationaryHaloPool = new LaserLinePool(((Component)this).transform, "StationaryHalo", 5000, halo, (LineTextureMode)0);
				_stationaryPool = new LaserLinePool(((Component)this).transform, "Stationary", 5001);
				_snapPool = new LaserLinePool(((Component)this).transform, "Snap", 5002);
				_movingHaloPool = new LaserLinePool(((Component)this).transform, "MovingHalo", 5003, halo, (LineTextureMode)0);
				_movingPool = new LaserLinePool(((Component)this).transform, "Moving", 5004);
				_alignedHaloPool = new LaserLinePool(((Component)this).transform, "AlignedHalo", 5005, halo, (LineTextureMode)0);
				_alignedPool = new LaserLinePool(((Component)this).transform, "Aligned", 5006);
			}
			catch (Exception ex)
			{
				_stationaryHaloPool = null;
				_stationaryPool = null;
				_snapPool = null;
				_movingHaloPool = null;
				_movingPool = null;
				_alignedHaloPool = null;
				_alignedPool = null;
				if (!_poolFailureLogged)
				{
					_poolFailureLogged = true;
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(116, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock][laser] line pools could not be created (logged once, fail-open); ");
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("the overlay draws nothing this session: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					log.LogError(val);
				}
			}
		}

		private void OnDisable()
		{
			BeginFrame();
		}

		private void LateUpdate()
		{
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Expected O, but got Unknown
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			BeginFrame();
			try
			{
				HasData = false;
				AlignmentSnapState.Clear();
				if (!GridLockConfig.LaserEnabled)
				{
					return;
				}
				GameObject val = SnapPatches.CurrentPreviewInstance();
				if (!((Object)(object)val == (Object)null) && val.activeInHierarchy && FootprintReader.TryRead(val, out var result))
				{
					LaserConfig laser = GridLockConfig.Laser;
					GridConfig grid = GridLockConfig.Grid;
					double cell = ((GridConfig)(ref grid)).Cell;
					Footprint2D footprint = result.Footprint;
					LaserLine[] array = GridReference.LinesFor(ref footprint, (double)result.PivotX, (double)result.PivotZ, cell, ((LaserConfig)(ref laser)).ExtensionLength);
					IReadOnlyList<WorldFootprint> readOnlyList = StationaryScan.Near(val.transform.position, ((LaserConfig)(ref laser)).DetectionDistance, ((LaserConfig)(ref laser)).ExtensionLength, ((LaserConfig)(ref laser)).HeightLimit, ((LaserConfig)(ref laser)).MinFootprintHalfExtent);
					_stationaryDraped = StationaryScan.LastDraped;
					StationaryLines.Clear();
					for (int i = 0; i < readOnlyList.Count; i++)
					{
						WorldFootprint worldFootprint = readOnlyList[i];
						List<LaserLine[]> stationaryLines = StationaryLines;
						footprint = worldFootprint.Footprint;
						stationaryLines.Add(GridReference.LinesFor(ref footprint, (double)worldFootprint.PivotX, (double)worldFootprint.PivotZ, cell, ((LaserConfig)(ref laser)).ExtensionLength));
					}
					Moving = result;
					MovingLines = array;
					Stationary = readOnlyList;
					Matches = LaserAlignment.Find(array, (IReadOnlyList<LaserLine[]>)StationaryLines, ((LaserConfig)(ref laser)).Tolerance);
					FreeMove = SnapPatches.IsFreeMove;
					HasData = true;
					AlignmentSnapState.Publish(in Moving, StationaryLines);
					Draw(laser);
				}
			}
			catch (Exception ex)
			{
				if (!_failureLogged)
				{
					_failureLogged = true;
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(74, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[GridLock][laser] LaserOverlay.LateUpdate threw (logged once, fail-open): ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
					}
					log.LogError(val2);
				}
			}
		}

		private void BeginFrame()
		{
			_stationaryHaloPool?.BeginFrame();
			_stationaryPool?.BeginFrame();
			_snapPool?.BeginFrame();
			_movingHaloPool?.BeginFrame();
			_movingPool?.BeginFrame();
			_alignedHaloPool?.BeginFrame();
			_alignedPool?.BeginFrame();
		}

		private void Draw(LaserConfig cfg)
		{
			//IL_0404: Unknown result type (might be due to invalid IL or missing references)
			//IL_040b: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_039a: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				double glowIntensity = ((LaserConfig)(ref cfg)).GlowIntensity;
				float num = (float)((LaserConfig)(ref cfg)).Thickness;
				float heightLimit = (float)((LaserConfig)(ref cfg)).HeightLimit;
				float floorY = Moving.FloorY;
				float topY = Moving.TopY;
				double pulse = PulseFactor();
				bool flag = ((LaserConfig)(ref cfg)).HaloScale > 0.0 && (Object)(object)LaserMaterial.GetHalo() != (Object)null;
				float haloWidth = (float)(((LaserConfig)(ref cfg)).Thickness * ((LaserConfig)(ref cfg)).HaloScale);
				Color stationaryRole = LaserPalette.StationaryRole;
				Color coreColor = LaserPalette.Core(stationaryRole, pulse);
				Color haloColor = LaserPalette.Halo(stationaryRole, glowIntensity);
				LaserLinePool haloPool = (flag ? _stationaryHaloPool : null);
				for (int i = 0; i < Stationary.Count && i < StationaryLines.Count; i++)
				{
					LaserLine[] array = StationaryLines[i];
					if (array == null)
					{
						continue;
					}
					List<Vector3>[] array2 = ((_stationaryDraped != null && i < _stationaryDraped.Count) ? _stationaryDraped[i] : null);
					WorldFootprint worldFootprint = Stationary[i];
					for (int j = 0; j < array.Length; j++)
					{
						if (LaserAlignment.IsRelevant(MovingLines, ref array[j], ((LaserConfig)(ref cfg)).ExtensionLength))
						{
							if (array2 != null && j < array2.Length && array2[j] != null)
							{
								AddCached(haloPool, _stationaryPool, array2[j], haloColor, haloWidth, coreColor, num);
							}
							else
							{
								AddDraped(haloPool, _stationaryPool, ((LaserLine)(ref array[j])).Laser, worldFootprint.FloorY, worldFootprint.TopY, heightLimit, haloColor, haloWidth, coreColor, num, _drapeBuffer);
							}
						}
					}
				}
				Color movingRole = LaserPalette.MovingRole;
				Color coreColor2 = LaserPalette.Core(movingRole, pulse);
				Color haloColor2 = LaserPalette.Halo(movingRole, glowIntensity);
				LaserLinePool haloPool2 = (flag ? _movingHaloPool : null);
				for (int k = 0; k < MovingLines.Length; k++)
				{
					AddDraped(haloPool2, _movingPool, ((LaserLine)(ref MovingLines[k])).Laser, floorY, topY, heightLimit, haloColor2, haloWidth, coreColor2, num, _drapeBuffer);
				}
				Color alignedRole = LaserPalette.AlignedRole;
				Color coreColor3 = LaserPalette.Core(alignedRole, pulse);
				Color haloColor3 = LaserPalette.Halo(alignedRole, glowIntensity);
				LaserLinePool haloPool3 = (flag ? _alignedHaloPool : null);
				float coreWidth = num * 1.3f;
				float haloWidth2 = (float)(((LaserConfig)(ref cfg)).Thickness * 1.2999999523162842 * ((LaserConfig)(ref cfg)).HaloScale);
				int num2 = ((Matches != null) ? Matches.Count : 0);
				for (int l = 0; l < num2; l++)
				{
					LaserLinePool alignedPool = _alignedPool;
					AlignmentMatch val = Matches[l];
					AddDraped(haloPool3, alignedPool, ((AlignmentMatch)(ref val)).Green, floorY, topY, heightLimit, haloColor3, haloWidth2, coreColor3, coreWidth, _drapeBuffer);
				}
				if (!FreeMove && _snapPool != null)
				{
					Footprint2D footprint = Moving.Footprint;
					double centerX = ((Footprint2D)(ref footprint)).CenterX;
					double centerZ = ((Footprint2D)(ref footprint)).CenterZ;
					GridConfig grid = GridLockConfig.Grid;
					List<(double, double)> list = SnapPoints.Around(centerX, centerZ, ((GridConfig)(ref grid)).Cell, ((LaserConfig)(ref cfg)).SnapIndicatorRadius, 1024);
					float num3 = (float)(((LaserConfig)(ref cfg)).SnapIndicatorSize * 0.5);
					float width = (float)((LaserConfig)(ref cfg)).SnapIndicatorThickness;
					Color snapRole = LaserPalette.SnapRole;
					for (int m = 0; m < list.Count; m++)
					{
						float num4 = (float)list[m].Item1;
						float num5 = (float)list[m].Item2;
						float num6 = LineDraper.HeightAt(num4, num5, floorY, topY, heightLimit);
						_snapPool.AddLine(new Vector3(num4 - num3, num6, num5), new Vector3(num4 + num3, num6, num5), snapRole, width);
						_snapPool.AddLine(new Vector3(num4, num6, num5 - num3), new Vector3(num4, num6, num5 + num3), snapRole, width);
					}
				}
			}
			catch (Exception ex)
			{
				if (!_drawFailureLogged)
				{
					_drawFailureLogged = true;
					ManualLogSource log = Plugin.Log;
					bool flag2 = default(bool);
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(68, 1, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[GridLock][laser] LaserOverlay.Draw threw (logged once, fail-open): ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
					}
					log.LogError(val2);
				}
			}
		}

		private static void AddDraped(LaserLinePool haloPool, LaserLinePool corePool, in Segment2D segment, float floorY, float topY, float heightLimit, Color haloColor, float haloWidth, Color coreColor, float coreWidth, List<Vector3> buffer)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (buffer != null && (haloPool != null || corePool != null))
			{
				LineDraper.Drape(in segment, floorY, topY, heightLimit, buffer);
				AddCached(haloPool, corePool, buffer, haloColor, haloWidth, coreColor, coreWidth);
			}
		}

		private static void AddCached(LaserLinePool haloPool, LaserLinePool corePool, List<Vector3> points, Color haloColor, float haloWidth, Color coreColor, float coreWidth)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			haloPool?.AddLine(points, haloColor, haloWidth);
			corePool?.AddLine(points, coreColor, coreWidth);
		}

		private static double PulseFactor()
		{
			if (!GridLockConfig.LaserPulseEnabled)
			{
				return 1.0;
			}
			return 1.0 + 0.08 * Math.Sin(Math.PI * 2.0 * (double)Time.unscaledTime);
		}
	}
	internal static class LaserPalette
	{
		private const double CoreWhitening = 0.15;

		private const double HaloAlphaScale = 0.25;

		private const float HaloAlphaMin = 0.05f;

		private const float HaloAlphaMax = 1f;

		internal static Color MovingRole => Role(0.2, 0.5, 1.0);

		internal static Color StationaryRole => Role(1.0, 0.85, 0.1);

		internal static Color AlignedRole => Role(0.2, 1.0, 0.3);

		internal static Color SnapRole => Role(1.0, 0.15, 0.15);

		internal static Color Core(Color role, double pulse)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			return new Color((float)(Whiten(role.r) * pulse), (float)(Whiten(role.g) * pulse), (float)(Whiten(role.b) * pulse), 1f);
		}

		internal static Color Halo(Color role, double glow)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp((float)(0.25 * glow), 0.05f, 1f);
			return new Color(role.r, role.g, role.b, num);
		}

		private static Color Role(double r, double g, double b)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return new Color((float)r, (float)g, (float)b, 1f);
		}

		private static double Whiten(double channel)
		{
			return channel + 0.15 * (1.0 - channel);
		}
	}
	internal static class LineDraper
	{
		internal const float Spacing = 0.5f;

		internal const float Lift = 0.25f;

		private const int MaxSamples = 256;

		internal static int Drape(in Segment2D seg, float floorY, float topY, float heightLimit, List<Vector3> into)
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			if (into == null)
			{
				return 0;
			}
			into.Clear();
			double aX = ((Segment2D)(ref seg)).AX;
			double aZ = ((Segment2D)(ref seg)).AZ;
			double num = ((Segment2D)(ref seg)).BX - aX;
			double num2 = ((Segment2D)(ref seg)).BZ - aZ;
			double num3 = Math.Sqrt(num * num + num2 * num2);
			int num4 = 1;
			if (!double.IsNaN(num3) && !double.IsInfinity(num3) && num3 > 0.5)
			{
				num4 = (int)Math.Ceiling(num3 / 0.5);
				if (num4 > 256)
				{
					num4 = 256;
				}
			}
			for (int i = 0; i <= num4; i++)
			{
				double num5 = (double)i / (double)num4;
				float num6 = (float)(aX + num * num5);
				float num7 = (float)(aZ + num2 * num5);
				into.Add(new Vector3(num6, HeightAt(num6, num7, floorY, topY, heightLimit), num7));
			}
			return into.Count;
		}

		internal static float HeightAt(float x, float z, float floorY, float topY, float heightLimit)
		{
			float num = floorY;
			if (TerrainHeight.TrySample(x, z, out var y) && !float.IsNaN(y) && !float.IsInfinity(y))
			{
				num = y;
			}
			float num2 = Math.Min(topY, num + heightLimit);
			float num3 = num + 0.25f;
			if (num3 < floorY)
			{
				num3 = floorY;
			}
			if (num3 > num2)
			{
				num3 = num2;
			}
			return num3;
		}
	}
	internal static class StationaryScan
	{
		private sealed class Entry
		{
			internal WorldFootprint Footprint;

			internal List<Vector3>[] Draped;

			internal bool Valid;

			internal bool Excluded;

			internal bool ExtentTested;

			internal float ReadAt;

			internal float SeenAt;

			internal long ScanId;
		}

		private const float ReacquireInterval = 1f;

		private const float RefreshInterval = 2f;

		private const float EvictInterval = 10f;

		private static Settlement[] _settlements;

		private static float _lastAcquire = -999f;

		private static bool _failureLogged;

		private static long _scanId;

		private static double _drapeExtension = double.NaN;

		private static double _drapeHeightLimit = double.NaN;

		private static double _minHalfExtent = double.NaN;

		private static readonly Dictionary<IntPtr, Entry> _cache = new Dictionary<IntPtr, Entry>();

		private static readonly List<WorldFootprint> _result = new List<WorldFootprint>();

		private static readonly List<List<Vector3>[]> _drapedResult = new List<List<Vector3>[]>();

		private static readonly List<IntPtr> _evict = new List<IntPtr>();

		internal static IReadOnlyList<List<Vector3>[]> LastDraped => _drapedResult;

		internal static IReadOnlyList<WorldFootprint> Near(Vector3 world, double radius, double extensionLength, double heightLimit, double minFootprintHalfExtent)
		{
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			_result.Clear();
			_drapedResult.Clear();
			try
			{
				if (radius <= 0.0)
				{
					return _result;
				}
				if (extensionLength != _drapeExtension || heightLimit != _drapeHeightLimit || minFootprintHalfExtent != _minHalfExtent)
				{
					_drapeExtension = extensionLength;
					_drapeHeightLimit = heightLimit;
					_minHalfExtent = minFootprintHalfExtent;
					_cache.Clear();
				}
				float unscaledTime = Time.unscaledTime;
				long num = ++_scanId;
				GameObject val = SnapPatches.CurrentPreviewInstance();
				IntPtr intPtr = (((Object)(object)val != (Object)null) ? ((Il2CppObjectBase)val).Pointer : IntPtr.Zero);
				if (_settlements == null || unscaledTime - _lastAcquire > 1f)
				{
					_settlements = Il2CppArrayBase<Settlement>.op_Implicit(Object.FindObjectsOfType<Settlement>());
					_lastAcquire = unscaledTime;
				}
				if (_settlements == null)
				{
					return _result;
				}
				for (int i = 0; i < _settlements.Length; i++)
				{
					Settlement val2 = _settlements[i];
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					List<Structure> val3 = new List<Structure>();
					Vector3 val4 = world;
					float num2 = (float)radius;
					val2.FindStructuresInRange(ref val4, ref num2, val3, (Predicate<Structure>)null);
					int num3 = val3?.Count ?? 0;
					for (int j = 0; j < num3; j++)
					{
						Structure val5 = val3[j];
						if ((Object)(object)val5 == (Object)null)
						{
							continue;
						}
						if (intPtr != IntPtr.Zero)
						{
							GameObject gameObject = ((Component)val5).gameObject;
							if ((Object)(object)gameObject != (Object)null && ((Il2CppObjectBase)gameObject).Pointer == intPtr)
							{
								continue;
							}
						}
						IntPtr pointer = ((Il2CppObjectBase)val5).Pointer;
						if (!_cache.TryGetValue(pointer, out var value))
						{
							value = new Entry
							{
								ReadAt = float.MinValue
							};
							_cache[pointer] = value;
							string text = ExclusionReason(val5);
							value.Excluded = text != null;
						}
						value.SeenAt = unscaledTime;
						if (value.Excluded)
						{
							continue;
						}
						if (unscaledTime - value.ReadAt > 2f)
						{
							value.Valid = FootprintReader.TryRead(((Component)val5).gameObject, out var result);
							value.Footprint = result;
							value.ReadAt = unscaledTime;
							value.Draped = (value.Valid ? Drape(result, extensionLength, heightLimit, value.Draped) : null);
						}
						if (!value.ExtentTested && value.Valid)
						{
							value.ExtentTested = true;
							if (IsBelowMinExtent(value.Footprint.Footprint, minFootprintHalfExtent))
							{
								value.Excluded = true;
								value.Draped = null;
								continue;
							}
						}
						if (value.Valid && value.ScanId != num)
						{
							value.ScanId = num;
							_result.Add(value.Footprint);
							_drapedResult.Add(value.Draped);
						}
					}
				}
				EvictStale(unscaledTime);
			}
			catch (Exception ex)
			{
				_result.Clear();
				_drapedResult.Clear();
				if (!_failureLogged)
				{
					_failureLogged = true;
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val6 = new BepInExErrorLogInterpolatedStringHandler(70, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("[GridLock][laser] StationaryScan.Near threw (logged once, fail-open): ");
						((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<Exception>(ex);
					}
					log.LogError(val6);
				}
			}
			return _result;
		}

		internal static void Reset()
		{
			_settlements = null;
			_minHalfExtent = double.NaN;
			_lastAcquire = -999f;
			_cache.Clear();
			_result.Clear();
			_drapedResult.Clear();
		}

		private static List<Vector3>[] Drape(WorldFootprint footprint, double extensionLength, double heightLimit, List<Vector3>[] reuse)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			Footprint2D footprint2 = footprint.Footprint;
			double num = footprint.PivotX;
			double num2 = footprint.PivotZ;
			GridConfig grid = GridLockConfig.Grid;
			LaserLine[] array = GridReference.LinesFor(ref footprint2, num, num2, ((GridConfig)(ref grid)).Cell, extensionLength);
			if (array.Length == 0)
			{
				return null;
			}
			List<Vector3>[] array2 = ((reuse != null && reuse.Length == array.Length) ? reuse : new List<Vector3>[array.Length]);
			for (int i = 0; i < array.Length; i++)
			{
				List<Vector3>[] array3 = array2;
				int num3 = i;
				if (array3[num3] == null)
				{
					array3[num3] = new List<Vector3>(32);
				}
				LineDraper.Drape(((LaserLine)(ref array[i])).Laser, footprint.FloorY, footprint.TopY, (float)heightLimit, array2[i]);
			}
			return array2;
		}

		private static string ExclusionReason(Structure str)
		{
			try
			{
				if ((Object)(object)str.Parent != (Object)null)
				{
					return "built into a parent structure";
				}
			}
			catch
			{
			}
			try
			{
				GameObject gameObject = ((Component)str).gameObject;
				string text = (((Object)(object)gameObject != (Object)null) ? ((Object)gameObject).name : null);
				if (!string.IsNullOrEmpty(text) && text.IndexOf("flag", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return "name contains \"flag\"";
				}
			}
			catch
			{
			}
			return null;
		}

		private static bool IsBelowMinExtent(Footprint2D footprint, double minHalfExtent)
		{
			if (((Footprint2D)(ref footprint)).HalfX < minHalfExtent)
			{
				return ((Footprint2D)(ref footprint)).HalfZ < minHalfExtent;
			}
			return false;
		}

		private static void EvictStale(float now)
		{
			_evict.Clear();
			foreach (KeyValuePair<IntPtr, Entry> item in _cache)
			{
				if (now - item.Value.SeenAt > 10f)
				{
					_evict.Add(item.Key);
				}
			}
			for (int i = 0; i < _evict.Count; i++)
			{
				_cache.Remove(_evict[i]);
			}
			_evict.Clear();
		}
	}
	internal static class TerrainHeight
	{
		private const float ReacquireInterval = 1f;

		private const float RaycastStartY = 200f;

		private const float RaycastMaxDistance = 400f;

		private static Terrain[] _terrains;

		private static float _lastAcquire = -999f;

		private static bool _failureLogged;

		internal static bool TrySample(float x, float z, out float y)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			y = 0f;
			try
			{
				if (_terrains == null || Time.unscaledTime - _lastAcquire > 1f)
				{
					_terrains = Il2CppArrayBase<Terrain>.op_Implicit((Il2CppArrayBase<Terrain>)(object)Terrain.activeTerrains);
					_lastAcquire = Time.unscaledTime;
				}
				int num = ((_terrains != null) ? _terrains.Length : 0);
				for (int i = 0; i < num; i++)
				{
					Terrain val = _terrains[i];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					TerrainData terrainData = val.terrainData;
					if (!((Object)(object)terrainData == (Object)null))
					{
						Vector3 position = ((Component)val).transform.position;
						Vector3 size = terrainData.size;
						if (!(x < position.x) && !(x > position.x + size.x) && !(z < position.z) && !(z > position.z + size.z))
						{
							y = val.SampleHeight(new Vector3(x, position.y, z)) + position.y;
							return true;
						}
					}
				}
				return TryRaycast(x, z, out y);
			}
			catch (Exception ex)
			{
				LogOnce("TrySample", ex);
				return false;
			}
		}

		private static bool TryRaycast(float x, float z, out float y)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			y = 0f;
			Il2CppStructArray<RaycastHit> val = Physics.RaycastAll(new Vector3(x, 200f, z), Vector3.down, 400f);
			int num = ((Il2CppArrayBase<RaycastHit>)(object)val)?.Length ?? 0;
			bool flag = false;
			float num2 = float.NegativeInfinity;
			bool flag2 = false;
			float num3 = float.NegativeInfinity;
			for (int i = 0; i < num; i++)
			{
				RaycastHit val2 = ((Il2CppArrayBase<RaycastHit>)(object)val)[i];
				Collider collider = ((RaycastHit)(ref val2)).collider;
				if (!((Object)(object)collider == (Object)null))
				{
					float y2 = ((RaycastHit)(ref val2)).point.y;
					if ((Object)(object)((Component)collider).gameObject.GetComponent<Terrain>() != (Object)null && (!flag || y2 > num2))
					{
						flag = true;
						num2 = y2;
					}
					if (!flag2 || y2 > num3)
					{
						flag2 = true;
						num3 = y2;
					}
				}
			}
			if (flag)
			{
				y = num2;
				return true;
			}
			if (flag2)
			{
				y = num3;
				return true;
			}
			return false;
		}

		private static void LogOnce(string where, Exception ex)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (!_failureLogged)
			{
				_failureLogged = true;
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(65, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[GridLock][laser] TerrainHeight.");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(where);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" threw (logged once, fail-open): ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}
	}
	internal readonly struct WorldFootprint
	{
		internal Footprint2D Footprint { get; }

		internal float FloorY { get; }

		internal float TopY { get; }

		internal float PivotX { get; }

		internal float PivotZ { get; }

		internal WorldFootprint(Footprint2D footprint, float floorY, float topY, float pivotX, float pivotZ)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			Footprint = footprint;
			FloorY = floorY;
			TopY = topY;
			PivotX = pivotX;
			PivotZ = pivotZ;
		}
	}
	internal static class NeighbourPosts
	{
		private static Settlement[] _settlements;

		private static float _lastAcquire = -999f;

		private const float ReacquireInterval = 1f;

		private const double DedupeEps = 0.05;

		private static bool _failureLogged;

		internal static List<(double X, double Z)> FindNear(Vector3 world, double radius)
		{
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: 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_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			List<(double, double)> list = new List<(double, double)>();
			try
			{
				if (radius <= 0.0)
				{
					return list;
				}
				float num = (float)radius;
				float num2 = num * num;
				float num3 = ((num < 8f) ? 8f : num);
				float unscaledTime = Time.unscaledTime;
				if (_settlements == null || unscaledTime - _lastAcquire > 1f)
				{
					_settlements = Il2CppArrayBase<Settlement>.op_Implicit(Object.FindObjectsOfType<Settlement>());
					_lastAcquire = unscaledTime;
				}
				if (_settlements == null)
				{
					return list;
				}
				for (int i = 0; i < _settlements.Length; i++)
				{
					Settlement val = _settlements[i];
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					List<Structure> val2 = new List<Structure>();
					Vector3 val3 = world;
					float num4 = num3;
					val.FindStructuresInRange(ref val3, ref num4, val2, (Predicate<Structure>)null);
					int num5 = val2?.Count ?? 0;
					for (int j = 0; j < num5; j++)
					{
						Structure val4 = val2[j];
						if ((Object)(object)val4 == (Object)null)
						{
							continue;
						}
						Il2CppArrayBase<Anchor> componentsInChildren = ((Component)val4).GetComponentsInChildren<Anchor>(true);
						int num6 = componentsInChildren?.Length ?? 0;
						for (int k = 0; k < num6; k++)
						{
							Anchor val5 = componentsInChildren[k];
							if (!((Object)(object)val5 == (Object)null))
							{
								Vector3 position = ((Component)val5).transform.position;
								float num7 = position.x - world.x;
								float num8 = position.z - world.z;
								if (!(num7 * num7 + num8 * num8 > num2))
								{
									AddUnique(list, position.x, position.z);
								}
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				if (!_failureLogged)
				{
					_failureLogged = true;
					ManualLogSource log = Plugin.Log;
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val6 = new BepInExErrorLogInterpolatedStringHandler(67, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("[GridLock] NeighbourPosts.FindNear threw (logged once, fail-open): ");
						((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<Exception>(ex);
					}
					log.LogError(val6);
				}
			}
			return list;
		}

		private static void AddUnique(List<(double X, double Z)> list, double x, double z)
		{
			for (int i = 0; i < list.Count; i++)
			{
				double num = list[i].X - x;
				double num2 = list[i].Z - z;
				if (num * num + num2 * num2 <= 0.0025000000000000005)
				{
					return;
				}
			}
			list.Add((x, z));
		}

		internal static void Reset()
		{
			_settlements = null;
			_lastAcquire = -999f;
		}
	}
	[BepInPlugin("mugsy33.gridlock", "Grid Lock", "1.2.0")]
	public class Plugin : BasePlugin
	{
		public const string PluginGuid = "mugsy33.gridlock";

		public const string PluginName = "Grid Lock";

		public const string PluginVersion = "1.2.0";

		internal static ManualLogSource Log;

		public override void Load()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			Log = ((BasePlugin)this).Log;
			ClassInjector.RegisterTypeInIl2Cpp<GridLockTool>();
			ClassInjector.RegisterTypeInIl2Cpp<LaserOverlay>();
			Harmony.CreateAndPatchAll(typeof(CharacterSpawnPatch), (string)null);
			GridLockConfig.Init(((BasePlugin)this).Config);
			SnapPatches.Arm(new Harmony("mugsy33.gridlock.snap"));
			TerrainSnapPatches.Arm(new Harmony("mugsy33.gridlock.terrain"));
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(10, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Grid Lock");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" v");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.2.0");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded.");
			}
			log.LogInfo(val);
		}
	}
	internal static class SessionState
	{
		private static PlayerBuilder _builder;

		internal static PlayerBuilder ResolveBuilder()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			try
			{
				if ((Object)(object)_builder != (Object)null)
				{
					return _builder;
				}
				Character localCharacter = CharacterSpawnPatch.LocalCharacter;
				if ((Object)(object)localCharacter != (Object)null)
				{
					PlayerBuilder val = ((Component)localCharacter).GetComponentInChildren<PlayerBuilder>(true);
					if ((Object)(object)val == (Object)null)
					{
						val = ((Component)localCharacter).GetComponentInParent<PlayerBuilder>();
					}
					if ((Object)(object)val != (Object)null)
					{
						_builder = val;
						return _builder;
					}
				}
				_builder = Object.FindObjectOfType<PlayerBuilder>();
				return _builder;
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(52, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[GridLock] resolving the local PlayerBuilder threw: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				log.LogError(val2);
				return null;
			}
		}

		internal static bool IsLocalPlacementTool(PlacementTool tool)
		{
			try
			{
				if ((Object)(object)tool == (Object)null)
				{
					return false;
				}
				PlayerBuilder val = ResolveBuilder();
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				PlacementTool placementTool = val._placementTool;
				if ((Object)(object)placementTool == (Object)null)
				{
					return false;
				}
				return ((Il2CppObjectBase)placementTool).Pointer == ((Il2CppObjectBase)tool).Pointer;
			}
			catch
			{
				return false;
			}
		}

		internal static void OnBuildModeExited()
		{
			_builder = null;
		}
	}
	internal static class SnapPatches
	{
		private static bool _snapFailureLogged;

		private static bool _endFailureLogged;

		private static bool _tickFailureLogged;

		private static bool _alignSnapFailureLogged;

		private static readonly FreeModeState Free = new FreeModeState();

		private static bool _haveWrite;

		private static Vector3 _lastPos;

		private static Quaternion _lastRot = Quaternion.identity;

		private static Vector3 _rawPos;

		private static float _rawYaw;

		private static float _rawPitch;

		private static float _rawRoll;

		private static GridPose _cachedShown;

		private static GridPose _cachedRaw;

		private static bool _wasDown;

		private static IntPtr _templatePtr = IntPtr.Zero;

		private const float PosEps = 0.001f;

		private const float RotEps = 0.05f;

		private static readonly List<Vector3> _ghostPoleBuf = new List<Vector3>();

		internal static bool IsFreeMove => Free.IsFree;

		internal static void Arm(Harmony harmony)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			HarmonyMethod postfix = new HarmonyMethod(typeof(SnapPatches), "SnapPostfix", (Type[])null);
			Type[] parameters = new Type[1] { typeof(Ray) };
			ArmDeclared(harmony, typeof(AnchorPointPlacementTool), "_OnBuildRayChanged", parameters, required: true, null, postfix);
			ArmDeclared(harmony, typeof(SkewedAnchorPointPlacementTool), "_OnBuildRayChanged", parameters, required: false, null, postfix);
			Type[] parameters2 = new Type[2]
			{
				typeof(NodeStructurePreviewData),
				typeof(AnchorPointPlacement)
			};
			ArmDeclared(harmony, typeof(AnchorPointPlacementTool), "_ValidatePlacement", parameters2, required: true, null, postfix);
			ArmDeclared(harmony, typeof(SkewedAnchorPointPlacementTool), "_ValidatePlacement", parameters2, required: false, null, postfix);
			HarmonyMethod postfix2 = new HarmonyMethod(typeof(SnapPatches), "EndBuildingPostfix", (Type[])null);
			ArmDeclared(harmony, typeof(PlayerBuilder), "_EndBuilding", Type.EmptyTypes, required: true, null, postfix2);
			ArmDeclared(harmony, typeof(PlayerBuilder_NewController), "_EndBuilding", Type.EmptyTypes, required: false, null, postfix2);
			ArmDeclared(harmony, typeof(PlayerBuilder_Invector), "_EndBuilding", Type.EmptyTypes, required: false, null, postfix2);
			ArmDeclared(harmony, typeof(PlayerBuilder_Naughty), "_EndBuilding", Type.EmptyTypes, required: false, null, postfix2);
		}

		private static void SnapPostfix(AnchorPointPlacementTool __instance)
		{
			Apply(__instance);
		}

		private static void Apply(AnchorPointPlacementTool __instance)
		{
			//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03de: Expected O, but got Unknown
			//IL_04c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c8: Expected O, but got Unknown
			//IL_040d: Unknown result type (might be due to invalid IL or missing references)
			//IL_040f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Unknown result type (might be due to invalid IL or missing references)
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_044e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0453: Unknown result type (might be due to invalid IL or missing references)
			//IL_0456: Unknown result type (might be due to invalid IL or missing references)
			//IL_045e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0465: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_046c: Unknown result type (might be due to invalid IL or missing references)
			//IL_046e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			//IL_049f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invali

GridLock.Core.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Microsoft.CodeAnalysis;

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

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AskaGridLock.Core
{
	public sealed class FreeModeState
	{
		private GridPose _offset;

		public bool IsFree { get; private set; }

		public void EnterFree(GridPose shownPose, GridPose rawPose)
		{
			_offset = shownPose - rawPose;
			IsFree = true;
		}

		public GridPose PoseWhileFree(GridPose rawPose)
		{
			return rawPose + _offset;
		}

		public void ExitFree()
		{
			_offset = default(GridPose);
			IsFree = false;
		}

		public void Reset()
		{
			_offset = default(GridPose);
			IsFree = false;
		}
	}
	public readonly struct GridConfig
	{
		public const double MinSpacing = 0.01;

		public const double MaxSpacing = 100.0;

		public const double MinRotationStep = 1.0;

		public const double MaxRotationStep = 180.0;

		public const double MinSquareSize = 0.01;

		public const double MaxSquareSize = 1000.0;

		public const double MinPostSnapRadius = 0.0;

		public const double MaxPostSnapRadius = 3.0;

		public double Spacing { get; }

		public double RotationStep { get; }

		public double SquareSize { get; }

		public double PostSnapRadius { get; }

		public double Cell { get; }

		public bool IsUsable
		{
			get
			{
				if (IsFinite(Spacing) && Spacing > 0.0 && IsFinite(RotationStep) && RotationStep > 0.0 && IsFinite(SquareSize) && SquareSize > 0.0 && IsFinite(Cell))
				{
					return Cell > 0.0;
				}
				return false;
			}
		}

		public GridConfig(double spacing, double rotationStep, double squareSize, double postSnapRadius)
		{
			Spacing = Clamp(spacing, 0.01, 100.0);
			RotationStep = Clamp(rotationStep, 1.0, 180.0);
			SquareSize = Clamp(squareSize, 0.01, 1000.0);
			PostSnapRadius = Clamp(postSnapRadius, 0.0, 3.0);
			Cell = Spacing * SquareSize;
		}

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

		private static double Clamp(double value, double min, double max)
		{
			if (double.IsNaN(value))
			{
				return min;
			}
			if (double.IsPositiveInfinity(value))
			{
				return max;
			}
			if (double.IsNegativeInfinity(value))
			{
				return min;
			}
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}
	}
	public readonly struct GridPose
	{
		public double X { get; }

		public double Z { get; }

		public double Yaw { get; }

		public GridPose(double x, double z, double yaw)
		{
			X = x;
			Z = z;
			Yaw = yaw;
		}

		public static GridPose operator +(GridPose a, GridPose b)
		{
			return new GridPose(a.X + b.X, a.Z + b.Z, a.Yaw + b.Yaw);
		}

		public static GridPose operator -(GridPose a, GridPose b)
		{
			return new GridPose(a.X - b.X, a.Z - b.Z, a.Yaw - b.Yaw);
		}
	}
	public static class PostSnap
	{
		public static (double X, double Z) Choose(double rawX, double rawZ, double gridX, double gridZ, IReadOnlyList<(double X, double Z)> neighbours, double radius)
		{
			if (radius <= 0.0 || !GridConfig.IsFinite(rawX) || !GridConfig.IsFinite(rawZ) || neighbours == null || neighbours.Count == 0)
			{
				return (X: gridX, Z: gridZ);
			}
			bool flag = false;
			double num = 0.0;
			double item = 0.0;
			double item2 = 0.0;
			for (int i = 0; i < neighbours.Count; i++)
			{
				double item3 = neighbours[i].X;
				double item4 = neighbours[i].Z;
				if (GridConfig.IsFinite(item3) && GridConfig.IsFinite(item4))
				{
					double num2 = item3 - rawX;
					double num3 = item4 - rawZ;
					double num4 = num2 * num2 + num3 * num3;
					if (!flag || num4 < num)
					{
						flag = true;
						num = num4;
						item = item3;
						item2 = item4;
					}
				}
			}
			if (flag && num <= radius * radius)
			{
				return (X: item, Z: item2);
			}
			return (X: gridX, Z: gridZ);
		}
	}
	public static class SnapMath
	{
		public static double SnapAxis(double world, double cell)
		{
			if (!GridConfig.IsFinite(cell) || cell <= 0.0)
			{
				return world;
			}
			double num = Math.Round(world / cell, MidpointRounding.AwayFromZero) * cell;
			if (!GridConfig.IsFinite(num))
			{
				return world;
			}
			return num;
		}

		public static GridPose SnapPosition(GridPose pose, double cell)
		{
			return new GridPose(SnapAxis(pose.X, cell), SnapAxis(pose.Z, cell), pose.Yaw);
		}

		public static double SnapYaw(double yaw, double step)
		{
			if (!GridConfig.IsFinite(step) || step <= 0.0)
			{
				return yaw;
			}
			double num = Math.Round(yaw / step, MidpointRounding.AwayFromZero) * step;
			if (!GridConfig.IsFinite(num))
			{
				return yaw;
			}
			return NormalizeDegrees(num);
		}

		private static double NormalizeDegrees(double degrees)
		{
			double num = degrees % 360.0;
			if (num < 0.0)
			{
				num += 360.0;
			}
			if (num >= 360.0)
			{
				num -= 360.0;
			}
			return num;
		}
	}
}
namespace AskaGridLock.Core.Laser
{
	public readonly struct AlignmentMatch
	{
		public int MovingEdge { get; }

		public int StationaryIndex { get; }

		public int StationaryEdge { get; }

		public double Offset { get; }

		public Segment2D Green { get; }

		public AlignmentMatch(int movingEdge, int stationaryIndex, int stationaryEdge, double offset, Segment2D green)
		{
			MovingEdge = movingEdge;
			StationaryIndex = stationaryIndex;
			StationaryEdge = stationaryEdge;
			Offset = offset;
			Green = green;
		}
	}
	public static class AlignmentSnap
	{
		private readonly struct Candidate
		{
			internal double DirX { get; }

			internal double DirZ { get; }

			internal double OffsetX { get; }

			internal double OffsetZ { get; }

			internal double Offset { get; }

			internal int EdgeIndex { get; }

			internal int StationaryIndex { get; }

			internal int StationaryEdgeIndex { get; }

			internal Candidate(double dirX, double dirZ, double offsetX, double offsetZ, double offset, int edgeIndex, int stationaryIndex, int stationaryEdgeIndex)
			{
				DirX = dirX;
				DirZ = dirZ;
				OffsetX = offsetX;
				OffsetZ = offsetZ;
				Offset = offset;
				EdgeIndex = edgeIndex;
				StationaryIndex = stationaryIndex;
				StationaryEdgeIndex = stationaryEdgeIndex;
			}
		}

		private const double TieEpsilon = 1E-12;

		public static bool Compute(LaserLine[] moving, IReadOnlyList<LaserLine[]> stationary, double capture, out double dx, out double dz)
		{
			dx = 0.0;
			dz = 0.0;
			if (moving == null || moving.Length == 0 || stationary == null || stationary.Count == 0)
			{
				return false;
			}
			if (!GridConfig.IsFinite(capture) || capture <= 0.0)
			{
				return false;
			}
			if (!TryPick(moving, stationary, capture, perpendicularOnly: false, 0.0, 0.0, out var best))
			{
				return false;
			}
			dx = best.OffsetX;
			dz = best.OffsetZ;
			if (TryPick(Translate(moving, dx, dz), stationary, capture, perpendicularOnly: true, best.DirX, best.DirZ, out var best2))
			{
				dx += best2.OffsetX;
				dz += best2.OffsetZ;
			}
			return true;
		}

		private static bool TryPick(LaserLine[] moving, IReadOnlyList<LaserLine[]> stationary, double capture, bool perpendicularOnly, double referenceDirX, double referenceDirZ, out Candidate best)
		{
			best = default(Candidate);
			bool flag = false;
			for (int i = 0; i < moving.Length; i++)
			{
				LaserLine a = moving[i];
				if (perpendicularOnly && !IsPerpendicular(a.DirX, a.DirZ, referenceDirX, referenceDirZ))
				{
					continue;
				}
				for (int j = 0; j < stationary.Count; j++)
				{
					LaserLine[] array = stationary[j];
					if (array == null)
					{
						continue;
					}
					for (int k = 0; k < array.Length; k++)
					{
						LaserLine b = array[k];
						if (!LaserAlignment.AreParallel(in a, in b))
						{
							continue;
						}
						double num = SignedOffset(in a, in b);
						if (GridConfig.IsFinite(num) && !(Math.Abs(num) > capture) && LaserAlignment.LasersOverlap(in a, in b))
						{
							Candidate a2 = new Candidate(a.DirX, a.DirZ, num * a.DirZ, (0.0 - num) * a.DirX, Math.Abs(num), a.EdgeIndex, j, b.EdgeIndex);
							if (!flag || IsBetter(in a2, in best))
							{
								best = a2;
								flag = true;
							}
						}
					}
				}
			}
			return flag;
		}

		private static double SignedOffset(in LaserLine moving, in LaserLine stationary)
		{
			double num = stationary.Edge.AX - moving.Edge.AX;
			double num2 = stationary.Edge.AZ - moving.Edge.AZ;
			return num * moving.DirZ - num2 * moving.DirX;
		}

		private static bool IsPerpendicular(double ax, double az, double bx, double bz)
		{
			double num = Math.Acos(Math.Min(Math.Abs(ax * bx + az * bz), 1.0)) * 180.0 / Math.PI;
			return 90.0 - num <= 0.5;
		}

		private static bool IsBetter(in Candidate a, in Candidate b)
		{
			if (a.Offset < b.Offset - 1E-12)
			{
				return true;
			}
			if (a.Offset > b.Offset + 1E-12)
			{
				return false;
			}
			if (a.EdgeIndex != b.EdgeIndex)
			{
				return a.EdgeIndex < b.EdgeIndex;
			}
			if (a.StationaryIndex != b.StationaryIndex)
			{
				return a.StationaryIndex < b.StationaryIndex;
			}
			return a.StationaryEdgeIndex < b.StationaryEdgeIndex;
		}

		private static LaserLine[] Translate(LaserLine[] lines, double dx, double dz)
		{
			LaserLine[] array = new LaserLine[lines.Length];
			for (int i = 0; i < lines.Length; i++)
			{
				LaserLine laserLine = lines[i];
				array[i] = new LaserLine(laserLine.EdgeIndex, laserLine.DirX, laserLine.DirZ, new Segment2D(laserLine.Edge.AX + dx, laserLine.Edge.AZ + dz, laserLine.Edge.BX + dx, laserLine.Edge.BZ + dz), new Segment2D(laserLine.Laser.AX + dx, laserLine.Laser.AZ + dz, laserLine.Laser.BX + dx, laserLine.Laser.BZ + dz), laserLine.TMin, laserLine.TMax);
			}
			return array;
		}
	}
	public readonly struct Footprint2D
	{
		public double CenterX { get; }

		public double CenterZ { get; }

		public double YawDegrees { get; }

		public double HalfX { get; }

		public double HalfZ { get; }

		public bool IsValid
		{
			get
			{
				if (GridConfig.IsFinite(CenterX) && GridConfig.IsFinite(CenterZ) && GridConfig.IsFinite(YawDegrees) && GridConfig.IsFinite(HalfX) && HalfX > 0.0 && GridConfig.IsFinite(HalfZ))
				{
					return HalfZ > 0.0;
				}
				return false;
			}
		}

		public Footprint2D(double centerX, double centerZ, double yawDegrees, double halfX, double halfZ)
		{
			CenterX = centerX;
			CenterZ = centerZ;
			YawDegrees = yawDegrees;
			HalfX = halfX;
			HalfZ = halfZ;
		}

		public (double X, double Z)[] Corners()
		{
			(double, double) tuple = Right(YawDegrees);
			(double, double) tuple2 = Forward(YawDegrees);
			double num = HalfX * tuple.Item1;
			double num2 = HalfX * tuple.Item2;
			double num3 = HalfZ * tuple2.Item1;
			double num4 = HalfZ * tuple2.Item2;
			return new(double, double)[4]
			{
				(CenterX - num - num3, CenterZ - num2 - num4),
				(CenterX + num - num3, CenterZ + num2 - num4),
				(CenterX + num + num3, CenterZ + num2 + num4),
				(CenterX - num + num3, CenterZ - num2 + num4)
			};
		}

		public static (double X, double Z) Right(double yawDegrees)
		{
			double num = yawDegrees * Math.PI / 180.0;
			return (X: Math.Cos(num), Z: 0.0 - Math.Sin(num));
		}

		public static (double X, double Z) Forward(double yawDegrees)
		{
			double num = yawDegrees * Math.PI / 180.0;
			return (X: Math.Sin(num), Z: Math.Cos(num));
		}
	}
	public static class GridReference
	{
		public const double GridPivotTolerance = 0.02;

		public static bool IsOnGrid(double pivotX, double pivotZ, double cell)
		{
			if (!GridConfig.IsFinite(pivotX) || !GridConfig.IsFinite(pivotZ) || !GridConfig.IsFinite(cell) || cell <= 0.0)
			{
				return false;
			}
			if (DistanceToGridLine(pivotX, cell) <= 0.02)
			{
				return DistanceToGridLine(pivotZ, cell) <= 0.02;
			}
			return false;
		}

		public static bool IsCardinal(double yawDegrees)
		{
			if (!GridConfig.IsFinite(yawDegrees))
			{
				return false;
			}
			double num = yawDegrees % 90.0;
			if (num < 0.0)
			{
				num += 90.0;
			}
			return Math.Min(num, 90.0 - num) <= 0.5;
		}

		public static LaserLine[] LinesFor(in Footprint2D footprint, double pivotX, double pivotZ, double cell, double extensionLength)
		{
			if (!footprint.IsValid || !GridConfig.IsFinite(cell) || cell <= 0.0 || !GridConfig.IsFinite(extensionLength) || extensionLength <= 0.0)
			{
				return Array.Empty<LaserLine>();
			}
			if (!IsOnGrid(pivotX, pivotZ, cell) || !IsCardinal(footprint.YawDegrees))
			{
				return LaserGeometry.LinesOf(in footprint, extensionLength);
			}
			return CardinalGridLines(in footprint, cell, extensionLength);
		}

		private static LaserLine[] CardinalGridLines(in Footprint2D footprint, double cell, double extensionLength)
		{
			(double, double)[] array = footprint.Corners();
			double num = array[0].Item1;
			double num2 = array[0].Item1;
			double num3 = array[0].Item2;
			double num4 = array[0].Item2;
			for (int i = 1; i < array.Length; i++)
			{
				num = Math.Min(num, array[i].Item1);
				num2 = Math.Max(num2, array[i].Item1);
				num3 = Math.Min(num3, array[i].Item2);
				num4 = Math.Max(num4, array[i].Item2);
			}
			num = SnapToGridLine(num, cell);
			num2 = SnapToGridLine(num2, cell);
			num3 = SnapToGridLine(num3, cell);
			num4 = SnapToGridLine(num4, cell);
			if (num2 - num < cell * 0.5)
			{
				num2 = num + cell;
			}
			if (num4 - num3 < cell * 0.5)
			{
				num4 = num3 + cell;
			}
			return LaserGeometry.LinesOf(new Footprint2D((num + num2) * 0.5, (num3 + num4) * 0.5, 0.0, (num2 - num) * 0.5, (num4 - num3) * 0.5), extensionLength);
		}

		private static double SnapToGridLine(double value, double cell)
		{
			return Math.Round(value / cell, MidpointRounding.AwayFromZero) * cell;
		}

		private static double DistanceToGridLine(double value, double cell)
		{
			return Math.Abs(value - SnapToGridLine(value, cell));
		}
	}
	public static class LaserAlignment
	{
		public const double ParallelToleranceDegrees = 0.5;

		public static bool AreParallel(in LaserLine a, in LaserLine b)
		{
			return Math.Acos(Math.Min(Math.Abs(a.DirX * b.DirX + a.DirZ * b.DirZ), 1.0)) * 180.0 / Math.PI <= 0.5;
		}

		public static double PerpendicularOffset(in LaserLine a, in LaserLine b)
		{
			double num = b.Edge.AX - a.Edge.AX;
			double num2 = b.Edge.AZ - a.Edge.AZ;
			return Math.Abs(num * a.DirZ - num2 * a.DirX);
		}

		public static bool IsRelevant(LaserLine[] moving, in LaserLine stationary, double band)
		{
			if (moving == null)
			{
				return false;
			}
			for (int i = 0; i < moving.Length; i++)
			{
				LaserLine a = moving[i];
				if (AreParallel(in a, in stationary) && !(PerpendicularOffset(in a, in stationary) > band) && LasersOverlap(in a, in stationary))
				{
					return true;
				}
			}
			return false;
		}

		public static List<AlignmentMatch> Find(LaserLine[] moving, IReadOnlyList<LaserLine[]> stationary, double tolerance)
		{
			List<AlignmentMatch> list = new List<AlignmentMatch>();
			if (moving == null || moving.Length == 0 || stationary == null || stationary.Count == 0)
			{
				return list;
			}
			for (int i = 0; i < moving.Length; i++)
			{
				LaserLine a = moving[i];
				for (int j = 0; j < stationary.Count; j++)
				{
					LaserLine[] array = stationary[j];
					if (array == null)
					{
						continue;
					}
					LaserLine[] array2 = array;
					for (int k = 0; k < array2.Length; k++)
					{
						LaserLine b = array2[k];
						if (!AreParallel(in a, in b))
						{
							continue;
						}
						double num = PerpendicularOffset(in a, in b);
						if (!(num > tolerance))
						{
							(double Lo, double Hi) tuple = ProjectedInterval(in a, in b);
							double item = tuple.Lo;
							double item2 = tuple.Hi;
							double num2 = Math.Max(a.TMin, item);
							if (!(Math.Min(a.TMax, item2) - num2 <= 1E-09))
							{
								double num3 = Math.Min(a.TMin, item);
								double num4 = Math.Max(a.TMax, item2);
								double ax = a.Edge.AX + num3 * a.DirX;
								double az = a.Edge.AZ + num3 * a.DirZ;
								double bx = a.Edge.AX + num4 * a.DirX;
								double bz = a.Edge.AZ + num4 * a.DirZ;
								list.Add(new AlignmentMatch(a.EdgeIndex, j, b.EdgeIndex, num, new Segment2D(ax, az, bx, bz)));
							}
						}
					}
				}
			}
			return list;
		}

		internal static bool LasersOverlap(in LaserLine moving, in LaserLine stationary)
		{
			var (bLo, bHi) = ProjectedInterval(in moving, in stationary);
			return IntervalsOverlap(moving.TMin, moving.TMax, bLo, bHi);
		}

		private static (double Lo, double Hi) ProjectedInterval(in LaserLine moving, in LaserLine stationary)
		{
			double num = 0.0 - stationary.TMin;
			double val = Project(in moving, stationary.Edge.AX, stationary.Edge.AZ);
			double val2 = Project(in moving, stationary.Edge.BX, stationary.Edge.BZ);
			return (Lo: Math.Min(val, val2) - num, Hi: Math.Max(val, val2) + num);
		}

		private static double Project(in LaserLine line, double x, double z)
		{
			double num = x - line.Edge.AX;
			double num2 = z - line.Edge.AZ;
			return num * line.DirX + num2 * line.DirZ;
		}

		private static bool IntervalsOverlap(double aLo, double aHi, double bLo, double bHi)
		{
			if (aLo <= bHi)
			{
				return bLo <= aHi;
			}
			return false;
		}
	}
	public readonly struct LaserConfig
	{
		public const double MinExtensionLength = 0.5;

		public const double MaxExtensionLength = 20.0;

		public const double MinDetectionDistance = 1.0;

		public const double MaxDetectionDistance = 50.0;

		public const double MinTolerance = 0.001;

		public const double MaxTolerance = 0.5;

		public const double MinThickness = 0.005;

		public const double MaxThickness = 0.5;

		public const double MinGlowIntensity = 0.1;

		public const double MaxGlowIntensity = 5.0;

		public const double MinSnapIndicatorSize = 0.01;

		public const double MaxSnapIndicatorSize = 0.5;

		public const double MinSnapIndicatorRadius = 1.0;

		public const double MaxSnapIndicatorRadius = 50.0;

		public const double MinHeightLimit = 0.25;

		public const double MaxHeightLimit = 20.0;

		public const double MinMinFootprintHalfExtent = 0.0;

		public const double MaxMinFootprintHalfExtent = 5.0;

		public const double MinSnapCapture = 0.05;

		public const double MaxSnapCapture = 2.0;

		public const double MinHaloScale = 0.0;

		public const double MaxHaloScale = 10.0;

		public const double MinSnapIndicatorThickness = 0.005;

		public const double MaxSnapIndicatorThickness = 0.2;

		public double ExtensionLength { get; }

		public double DetectionDistance { get; }

		public double Tolerance { get; }

		public double Thickness { get; }

		public double GlowIntensity { get; }

		public double SnapIndicatorSize { get; }

		public double HeightLimit { get; }

		public double SnapIndicatorRadius { get; }

		public double MinFootprintHalfExtent { get; }

		public double SnapCapture { get; }

		public double HaloScale { get; }

		public double SnapIndicatorThickness { get; }

		public bool IsUsable
		{
			get
			{
				if (GridConfig.IsFinite(ExtensionLength) && ExtensionLength > 0.0 && GridConfig.IsFinite(DetectionDistance) && DetectionDistance > 0.0 && GridConfig.IsFinite(Tolerance) && Tolerance > 0.0 && GridConfig.IsFinite(Thickness) && Thickness > 0.0 && GridConfig.IsFinite(GlowIntensity) && GlowIntensity > 0.0 && GridConfig.IsFinite(SnapIndicatorSize) && SnapIndicatorSize > 0.0 && GridConfig.IsFinite(HeightLimit) && HeightLimit > 0.0 && GridConfig.IsFinite(SnapIndicatorRadius) && SnapIndicatorRadius > 0.0 && GridConfig.IsFinite(MinFootprintHalfExtent) && MinFootprintHalfExtent >= 0.0 && GridConfig.IsFinite(SnapCapture) && SnapCapture > 0.0 && GridConfig.IsFinite(HaloScale) && HaloScale >= 0.0 && GridConfig.IsFinite(SnapIndicatorThickness))
				{
					return SnapIndicatorThickness > 0.0;
				}
				return false;
			}
		}

		public LaserConfig(double extensionLength, double detectionDistance, double tolerance, double thickness, double glowIntensity, double snapIndicatorSize, double heightLimit, double snapIndicatorRadius, double minFootprintHalfExtent, double snapCapture, double haloScale, double snapIndicatorThickness)
		{
			ExtensionLength = Clamp(extensionLength, 0.5, 20.0);
			DetectionDistance = Clamp(detectionDistance, 1.0, 50.0);
			Tolerance = Clamp(tolerance, 0.001, 0.5);
			Thickness = Clamp(thickness, 0.005, 0.5);
			GlowIntensity = Clamp(glowIntensity, 0.1, 5.0);
			SnapIndicatorSize = Clamp(snapIndicatorSize, 0.01, 0.5);
			HeightLimit = Clamp(heightLimit, 0.25, 20.0);
			SnapIndicatorRadius = Clamp(snapIndicatorRadius, 1.0, 50.0);
			MinFootprintHalfExtent = Clamp(minFootprintHalfExtent, 0.0, 5.0);
			SnapCapture = Clamp(snapCapture, 0.05, 2.0);
			HaloScale = Clamp(haloScale, 0.0, 10.0);
			SnapIndicatorThickness = Clamp(snapIndicatorThickness, 0.005, 0.2);
		}

		private static double Clamp(double value, double min, double max)
		{
			if (double.IsNaN(value))
			{
				return min;
			}
			if (double.IsPositiveInfinity(value))
			{
				return max;
			}
			if (double.IsNegativeInfinity(value))
			{
				return min;
			}
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}
	}
	public static class LaserGeometry
	{
		public static LaserLine[] LinesOf(in Footprint2D footprint, double extensionLength)
		{
			if (!footprint.IsValid || !GridConfig.IsFinite(extensionLength) || extensionLength <= 0.0)
			{
				return Array.Empty<LaserLine>();
			}
			(double, double)[] array = footprint.Corners();
			LaserLine[] array2 = new LaserLine[4];
			for (int i = 0; i < 4; i++)
			{
				(double, double) tuple = array[i];
				(double, double) tuple2 = array[(i + 1) % 4];
				array2[i] = BuildLine(i, tuple.Item1, tuple.Item2, tuple2.Item1, tuple2.Item2, extensionLength);
			}
			return array2;
		}

		internal static LaserLine BuildLine(int edgeIndex, double ax, double az, double bx, double bz, double extensionLength)
		{
			Segment2D edge = new Segment2D(ax, az, bx, bz);
			double length = edge.Length;
			double num = ((length > 0.0) ? ((bx - ax) / length) : 0.0);
			double num2 = ((length > 0.0) ? ((bz - az) / length) : 0.0);
			return new LaserLine(laser: new Segment2D(ax - extensionLength * num, az - extensionLength * num2, bx + extensionLength * num, bz + extensionLength * num2), edgeIndex: edgeIndex, dirX: num, dirZ: num2, edge: edge, tMin: 0.0 - extensionLength, tMax: length + extensionLength);
		}
	}
	public readonly struct LaserLine
	{
		public int EdgeIndex { get; }

		public double DirX { get; }

		public double DirZ { get; }

		public Segment2D Edge { get; }

		public Segment2D Laser { get; }

		public double TMin { get; }

		public double TMax { get; }

		public LaserLine(int edgeIndex, double dirX, double dirZ, Segment2D edge, Segment2D laser, double tMin, double tMax)
		{
			EdgeIndex = edgeIndex;
			DirX = dirX;
			DirZ = dirZ;
			Edge = edge;
			Laser = laser;
			TMin = tMin;
			TMax = tMax;
		}
	}
	public readonly struct Segment2D
	{
		public double AX { get; }

		public double AZ { get; }

		public double BX { get; }

		public double BZ { get; }

		public double Length { get; }

		public Segment2D(double ax, double az, double bx, double bz)
		{
			AX = ax;
			AZ = az;
			BX = bx;
			BZ = bz;
			double num = bx - ax;
			double num2 = bz - az;
			Length = Math.Sqrt(num * num + num2 * num2);
		}
	}
	public static class SnapPoints
	{
		public static List<(double X, double Z)> Around(double centerX, double centerZ, double cell, double radius, int maxCount)
		{
			List<(double, double)> list = new List<(double, double)>();
			if (!GridConfig.IsFinite(centerX) || !GridConfig.IsFinite(centerZ) || !GridConfig.IsFinite(cell) || cell <= 0.0 || !GridConfig.IsFinite(radius) || radius <= 0.0 || maxCount <= 0)
			{
				return list;
			}
			int num = (int)Math.Round(centerX / cell, MidpointRounding.AwayFromZero);
			int num2 = (int)Math.Round(centerZ / cell, MidpointRounding.AwayFromZero);
			int num3 = (int)Math.Ceiling(radius / cell) + 1;
			for (int i = 0; i <= num3; i++)
			{
				if (list.Count >= maxCount)
				{
					break;
				}
				foreach (var item3 in RingOffsets(i))
				{
					int item = item3.I;
					int item2 = item3.J;
					double num4 = (double)(num + item) * cell;
					double num5 = (double)(num2 + item2) * cell;
					if (Math.Abs(num4 - centerX) <= radius && Math.Abs(num5 - centerZ) <= radius)
					{
						list.Add((num4, num5));
						if (list.Count >= maxCount)
						{
							break;
						}
					}
				}
			}
			return list;
		}

		private static IEnumerable<(int I, int J)> RingOffsets(int ring)
		{
			if (ring == 0)
			{
				yield return (I: 0, J: 0);
				yield break;
			}
			for (int i = -ring; i <= ring; i++)
			{
				yield return (I: i, J: -ring);
				yield return (I: i, J: ring);
			}
			for (int i = -ring + 1; i <= ring - 1; i++)
			{
				yield return (I: -ring, J: i);
				yield return (I: ring, J: i);
			}
		}
	}
}