Decompiled source of Procedural Roads v1.1.0

ProceduralRoads.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ProceduralRoads")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("warpalicious")]
[assembly: AssemblyProduct("ProceduralRoads")]
[assembly: AssemblyCopyright("Copyright ©  2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("E0E2F92E-557C-4A05-9D89-AA92A0BD75C4")]
[assembly: AssemblyFileVersion("1.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace ProceduralRoads
{
	public class RoadPointDebugMarker : MonoBehaviour, Interactable, Hoverable
	{
		public RoadSpatialGrid.RoadPointDebugInfo DebugInfo;

		public Vector2 RoadPointPosition;

		public float RoadPointHeight;

		private static ManualLogSource Log => ProceduralRoadsPlugin.ProceduralRoadsLogger;

		public string GetHoverName()
		{
			return "Road Point Debug";
		}

		public string GetHoverText()
		{
			float num = DebugInfo.SmoothedHeight - DebugInfo.OriginalHeight;
			string arg = ((num >= 0f) ? $"+{num:F2}m" : $"{num:F2}m");
			return $"[<color=yellow><b>$KEY_Use</b></color>] Inspect point {DebugInfo.PointIndex}/{DebugInfo.TotalPoints} ({arg})";
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (hold)
			{
				return false;
			}
			LogDebugInfo();
			return true;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}

		private void LogDebugInfo()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("=== Road Point Debug ===");
			stringBuilder.AppendLine($"Position: ({RoadPointPosition.x:F1}, {RoadPointPosition.y:F1})");
			stringBuilder.AppendLine($"Index: {DebugInfo.PointIndex} of {DebugInfo.TotalPoints} points in road");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine($"Terrain Height (blended): {DebugInfo.OriginalHeight:F2}m");
			stringBuilder.AppendLine($"Smoothed Road Height: {DebugInfo.SmoothedHeight:F2}m");
			float num = DebugInfo.SmoothedHeight - DebugInfo.OriginalHeight;
			string arg = ((num >= 0f) ? "road above terrain" : "road below terrain");
			stringBuilder.AppendLine($"Delta: {num:F2}m ({arg})");
			stringBuilder.AppendLine();
			int num2 = 20;
			int num3 = DebugInfo.PointIndex - num2;
			int num4 = DebugInfo.PointIndex + num2;
			stringBuilder.AppendLine("Smoothing Window:");
			stringBuilder.AppendLine($"  Requested: {41} points (idx {num3} to {num4})");
			string text = ((DebugInfo.ActualWindowSize >= 41) ? "[FULL WINDOW]" : ((DebugInfo.WindowStart != 0) ? "[TRUNCATED - at path end]" : "[TRUNCATED - at path start]"));
			stringBuilder.AppendLine($"  Actual: {DebugInfo.ActualWindowSize} points (idx {DebugInfo.WindowStart} to {DebugInfo.WindowEnd}) {text}");
			stringBuilder.AppendLine();
			if (DebugInfo.WindowHeights != null && DebugInfo.WindowHeights.Length != 0)
			{
				stringBuilder.AppendLine("Heights in Window:");
				int num5 = Mathf.Min(5, DebugInfo.WindowHeights.Length);
				StringBuilder stringBuilder2 = new StringBuilder("  First: ");
				for (int i = 0; i < num5; i++)
				{
					stringBuilder2.Append($"{DebugInfo.WindowHeights[i]:F1}m ");
				}
				stringBuilder.AppendLine(stringBuilder2.ToString());
				if (DebugInfo.WindowHeights.Length > num5 * 2)
				{
					stringBuilder.AppendLine("  ...");
					StringBuilder stringBuilder3 = new StringBuilder("  Last:  ");
					for (int j = DebugInfo.WindowHeights.Length - num5; j < DebugInfo.WindowHeights.Length; j++)
					{
						stringBuilder3.Append($"{DebugInfo.WindowHeights[j]:F1}m ");
					}
					stringBuilder.AppendLine(stringBuilder3.ToString());
				}
			}
			stringBuilder.AppendLine();
			if (WorldGenerator.instance != null)
			{
				float height = WorldGenerator.instance.GetHeight(RoadPointPosition.x, RoadPointPosition.y);
				float blendedHeight = BiomeBlendedHeight.GetBlendedHeight(RoadPointPosition.x, RoadPointPosition.y, WorldGenerator.instance);
				stringBuilder.AppendLine("Height Comparison:");
				stringBuilder.AppendLine($"  Raw WorldGen height: {height:F2}m");
				stringBuilder.AppendLine($"  Biome-blended height: {blendedHeight:F2}m");
				stringBuilder.AppendLine($"  Blend difference: {blendedHeight - height:F2}m");
				stringBuilder.AppendLine($"  Road target: {DebugInfo.SmoothedHeight:F2}m");
			}
			string text2 = stringBuilder.ToString();
			Log.LogDebug((object)text2);
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, $"Road point {DebugInfo.PointIndex}: delta={num:F2}m (see console)", 0, (Sprite)null);
			}
		}
	}
	public static class ZoneSystem_Patch
	{
		[HarmonyPatch(typeof(ZoneSystem), "Start")]
		public static class ZoneSystem_Start_Patch
		{
			[HarmonyPostfix]
			public static void Postfix(ZoneSystem __instance)
			{
				RoadNetworkGenerator.Initialize();
				__instance.GenerateLocationsCompleted += OnLocationsGenerated;
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)"Subscribed to GenerateLocationsCompleted event");
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "PlaceVegetation")]
		public static class ZoneSystem_PlaceVegetation_Patch
		{
			[HarmonyPrefix]
			public static void Prefix(Vector2i zoneID, List<ClearArea> clearAreas)
			{
				//IL_000d: 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_0023: Unknown result type (might be due to invalid IL or missing references)
				if (RoadNetworkGenerator.RoadsGenerated)
				{
					if (!s_roadClearAreasCache.TryGetValue(zoneID, out List<ClearArea> value))
					{
						value = CreateRoadClearAreas(zoneID);
						s_roadClearAreasCache[zoneID] = value;
					}
					clearAreas.AddRange(value);
				}
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "SpawnZone")]
		public static class ZoneSystem_SpawnZone_Patch
		{
			[HarmonyPostfix]
			public static void Postfix(ZoneSystem __instance, Vector2i zoneID, SpawnMode mode, ref bool __result)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Invalid comparison between Unknown and I4
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0157: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
				if ((int)mode == 1)
				{
					return;
				}
				if (RoadNetworkGenerator.IsLocationsReady && !RoadNetworkGenerator.RoadsAvailable)
				{
					if (TryLoadRoadDataFromZDO(zoneID))
					{
						RoadNetworkGenerator.MarkRoadsLoadedFromZDO();
						ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)"Roads found in ZDO, loading from persistence");
					}
					else
					{
						ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)"No roads in ZDO, generating (deferred)...");
						RoadNetworkGenerator.GenerateRoads();
						RoadNetworkGenerator.SaveRoadMetadata();
					}
				}
				if (__result && RoadNetworkGenerator.RoadsGenerated)
				{
					List<RoadSpatialGrid.RoadPoint> roadPointsInZone = RoadSpatialGrid.GetRoadPointsInZone(zoneID);
					if (roadPointsInZone.Count > 0)
					{
						s_zoneTimer.Restart();
						ApplyRoadTerrainModsAndPersist(zoneID, roadPointsInZone);
						s_zoneTimer.Stop();
						double totalMilliseconds = s_zoneTimer.Elapsed.TotalMilliseconds;
						s_timedZoneCount++;
						s_totalZoneTimeMs += totalMilliseconds;
						if (totalMilliseconds > s_maxZoneTimeMs)
						{
							s_maxZoneTimeMs = totalMilliseconds;
						}
						ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"Zone {zoneID}: {roadPointsInZone.Count} road points, {totalMilliseconds:F2}ms");
						if (s_timedZoneCount % 10 == 0)
						{
							double num = s_totalZoneTimeMs / (double)s_timedZoneCount;
							ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"[PERF] Road zones: {s_timedZoneCount} processed, {s_skippedZoneCount} loaded from ZDO, avg={num:F2}ms, max={s_maxZoneTimeMs:F2}ms");
						}
					}
				}
				else if (RoadNetworkGenerator.RoadsLoadedFromZDO)
				{
					TryLoadRoadDataFromZDO(zoneID);
				}
			}
		}

		private struct TerrainContext
		{
			public Heightmap Heightmap;

			public TerrainComp TerrainComp;

			public Vector3 HeightmapPosition;

			public int GridSize;

			public float VertexSpacing;
		}

		private struct ModificationStats
		{
			public int VerticesModified;

			public int VerticesChecked;

			public HashSet<Vector2i> PaintedCells;
		}

		private struct BlendResult
		{
			public float TargetHeight;

			public float MaxBlend;

			public int InfluencingPoints;
		}

		[HarmonyPatch(typeof(ZoneSystem), "OnDestroy")]
		public static class ZoneSystem_OnDestroy_Patch
		{
			[HarmonyPrefix]
			public static void Prefix(ZoneSystem __instance)
			{
				if (s_timedZoneCount > 0 || s_skippedZoneCount > 0)
				{
					double num = ((s_timedZoneCount > 0) ? (s_totalZoneTimeMs / (double)s_timedZoneCount) : 0.0);
					ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)($"[PERF FINAL] Road zones: {s_timedZoneCount} processed, {s_skippedZoneCount} skipped, " + $"avg={num:F2}ms, max={s_maxZoneTimeMs:F2}ms, total={s_totalZoneTimeMs:F0}ms"));
				}
				__instance.GenerateLocationsCompleted -= OnLocationsGenerated;
				RoadNetworkGenerator.Reset();
				s_roadClearAreasCache.Clear();
				s_coordLogCount = 0;
				s_timedZoneCount = 0;
				s_totalZoneTimeMs = 0.0;
				s_maxZoneTimeMs = 0.0;
				s_skippedZoneCount = 0;
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)"Road data cleared on world unload");
			}
		}

		[HarmonyPatch(typeof(Game), "SpawnPlayer")]
		public static class Game_SpawnPlayer_Patch
		{
			[HarmonyPostfix]
			public static void Postfix(Vector3 spawnPoint)
			{
				//IL_0019: 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_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: 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_0057: Unknown result type (might be due to invalid IL or missing references)
				if (!RoadNetworkGenerator.IsLocationsReady || RoadNetworkGenerator.RoadsAvailable)
				{
					return;
				}
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"Player spawning at {spawnPoint}, loading road data from ZDOs...");
				RoadNetworkGenerator.MarkRoadsLoadedFromZDO();
				RoadNetworkGenerator.TryLoadRoadMetadata();
				Vector2i zone = ZoneSystem.GetZone(spawnPoint);
				int num = 0;
				for (int i = -2; i <= 2; i++)
				{
					for (int j = -2; j <= 2; j++)
					{
						if (TryLoadRoadDataFromZDO(new Vector2i(zone.x + i, zone.y + j)))
						{
							num++;
						}
					}
				}
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"Loaded road data from {num} zones near player");
			}
		}

		private static readonly Dictionary<Vector2i, List<ClearArea>> s_roadClearAreasCache = new Dictionary<Vector2i, List<ClearArea>>();

		private static int s_coordLogCount = 0;

		private static readonly Stopwatch s_zoneTimer = new Stopwatch();

		private static int s_timedZoneCount = 0;

		private static double s_totalZoneTimeMs = 0.0;

		private static double s_maxZoneTimeMs = 0.0;

		private const int TimingLogInterval = 10;

		private static int s_skippedZoneCount = 0;

		private static void OnLocationsGenerated()
		{
			ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)"Location generation complete...");
			RoadNetworkGenerator.MarkLocationsReady();
			s_roadClearAreasCache.Clear();
			bool flag = WorldGenerator.instance != null;
			ZoneSystem instance = ZoneSystem.instance;
			bool flag2 = instance != null && instance.GetLocationList()?.Count > 0;
			if (flag && flag2)
			{
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"WorldGenerator and locations available ({ZoneSystem.instance.GetLocationList().Count} locations), generating roads now...");
				RoadNetworkGenerator.GenerateRoads();
				RoadNetworkGenerator.SaveRoadMetadata();
			}
			else
			{
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"Deferring road generation (WorldGen={flag}, Locations={flag2})...");
			}
		}

		private static List<ClearArea> CreateRoadClearAreas(Vector2i zoneID)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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_0072: 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_008f: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			List<ClearArea> list = new List<ClearArea>();
			List<RoadSpatialGrid.RoadPoint> roadPointsInZone = RoadSpatialGrid.GetRoadPointsInZone(zoneID);
			if (roadPointsInZone.Count == 0)
			{
				return list;
			}
			HashSet<Vector2i> hashSet = new HashSet<Vector2i>();
			Vector2i val = default(Vector2i);
			Vector3 val2 = default(Vector3);
			foreach (RoadSpatialGrid.RoadPoint item in roadPointsInZone)
			{
				((Vector2i)(ref val))..ctor(Mathf.RoundToInt(item.p.x / 4f), Mathf.RoundToInt(item.p.y / 4f));
				if (!hashSet.Contains(val))
				{
					hashSet.Add(val);
					((Vector3)(ref val2))..ctor((float)val.x * 4f, 0f, (float)val.y * 4f);
					float num = item.w * 0.6f;
					list.Add(new ClearArea(val2, num));
				}
			}
			return list;
		}

		private static bool TryLoadRoadDataFromZDO(Vector2i zoneID)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			Heightmap val = Heightmap.FindHeightmap(ZoneSystem.GetZonePos(zoneID));
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			TerrainComp andCreateTerrainCompiler = val.GetAndCreateTerrainCompiler();
			if ((Object)(object)andCreateTerrainCompiler == (Object)null || !andCreateTerrainCompiler.m_nview.IsValid())
			{
				return false;
			}
			byte[] byteArray = andCreateTerrainCompiler.m_nview.GetZDO().GetByteArray(RoadSpatialGrid.RoadDataHash, (byte[])null);
			if (byteArray != null && byteArray.Length != 0)
			{
				RoadSpatialGrid.DeserializeZoneRoadPoints(zoneID, byteArray);
				s_skippedZoneCount++;
				if (s_skippedZoneCount <= 5 || s_skippedZoneCount % 20 == 0)
				{
					ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"Zone {zoneID}: loaded {byteArray.Length} bytes from ZDO, total loaded: {s_skippedZoneCount}");
				}
				return true;
			}
			return false;
		}

		private static void ApplyRoadTerrainModsAndPersist(Vector2i zoneID, List<RoadSpatialGrid.RoadPoint> roadPoints)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			TerrainContext? terrainContext = GetTerrainContext(zoneID);
			if (!terrainContext.HasValue)
			{
				return;
			}
			if (terrainContext.Value.TerrainComp.m_nview.IsValid() && terrainContext.Value.TerrainComp.m_nview.IsOwner())
			{
				byte[] array = RoadSpatialGrid.SerializeZoneRoadPoints(zoneID);
				if (array != null)
				{
					terrainContext.Value.TerrainComp.m_nview.GetZDO().Set(RoadSpatialGrid.RoadDataHash, array);
				}
			}
			ModificationStats stats = ModifyVertexHeights(zoneID, roadPoints, terrainContext.Value);
			ApplyRoadPaint(roadPoints, terrainContext.Value.TerrainComp, stats.PaintedCells);
			FinalizeTerrainMods(zoneID, roadPoints.Count, stats, terrainContext.Value);
		}

		public static void ApplyRoadTerrainModsPublic(Vector2i zoneID, List<RoadSpatialGrid.RoadPoint> roadPoints, Heightmap heightmap, TerrainComp terrainComp)
		{
			//IL_0034: 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_008d: 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)
			if (roadPoints != null && roadPoints.Count != 0)
			{
				int num = terrainComp.m_width + 1;
				if (terrainComp.m_levelDelta == null || terrainComp.m_levelDelta.Length < num * num)
				{
					ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"Zone {zoneID}: TerrainComp arrays not initialized");
					return;
				}
				TerrainContext terrainContext = default(TerrainContext);
				terrainContext.Heightmap = heightmap;
				terrainContext.TerrainComp = terrainComp;
				terrainContext.HeightmapPosition = ((Component)heightmap).transform.position;
				terrainContext.GridSize = num;
				terrainContext.VertexSpacing = 64f / (float)terrainComp.m_width;
				TerrainContext context = terrainContext;
				ModificationStats stats = ModifyVertexHeights(zoneID, roadPoints, context);
				ApplyRoadPaint(roadPoints, context.TerrainComp, stats.PaintedCells);
				FinalizeTerrainMods(zoneID, roadPoints.Count, stats, context);
			}
		}

		private static TerrainContext? GetTerrainContext(Vector2i zoneID)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: 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_0053: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			Heightmap val = Heightmap.FindHeightmap(ZoneSystem.GetZonePos(zoneID));
			if ((Object)(object)val == (Object)null)
			{
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"No heightmap found for zone {zoneID}");
				return null;
			}
			TerrainComp andCreateTerrainCompiler = val.GetAndCreateTerrainCompiler();
			if ((Object)(object)andCreateTerrainCompiler == (Object)null)
			{
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"Could not get TerrainComp for zone {zoneID}");
				return null;
			}
			if (!andCreateTerrainCompiler.m_nview.IsOwner())
			{
				return null;
			}
			int num = andCreateTerrainCompiler.m_width + 1;
			if (andCreateTerrainCompiler.m_levelDelta == null || andCreateTerrainCompiler.m_levelDelta.Length < num * num)
			{
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"Zone {zoneID}: TerrainComp arrays not initialized");
				return null;
			}
			TerrainContext value = default(TerrainContext);
			value.Heightmap = val;
			value.TerrainComp = andCreateTerrainCompiler;
			value.HeightmapPosition = ((Component)val).transform.position;
			value.GridSize = num;
			value.VertexSpacing = 64f / (float)andCreateTerrainCompiler.m_width;
			return value;
		}

		private static ModificationStats ModifyVertexHeights(Vector2i zoneID, List<RoadSpatialGrid.RoadPoint> roadPoints, TerrainContext context)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_00aa: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			ModificationStats modificationStats = default(ModificationStats);
			modificationStats.PaintedCells = new HashSet<Vector2i>();
			ModificationStats result = modificationStats;
			LogCoordinateDebug(zoneID, roadPoints, context);
			Vector3 val = default(Vector3);
			Vector2 vertexPos = default(Vector2);
			for (int i = 0; i < context.GridSize; i++)
			{
				for (int j = 0; j < context.GridSize; j++)
				{
					result.VerticesChecked++;
					((Vector3)(ref val))..ctor(context.HeightmapPosition.x + ((float)j - (float)context.TerrainComp.m_width / 2f) * context.VertexSpacing, 0f, context.HeightmapPosition.z + ((float)i - (float)context.TerrainComp.m_width / 2f) * context.VertexSpacing);
					((Vector2)(ref vertexPos))..ctor(val.x, val.z);
					BlendResult blendResult = CalculateBlendedHeight(roadPoints, vertexPos);
					if (blendResult.InfluencingPoints == 0)
					{
						continue;
					}
					float blendedHeight = BiomeBlendedHeight.GetBlendedHeight(val.x, val.z, WorldGenerator.instance);
					float num = Mathf.Clamp(Mathf.Lerp(blendedHeight, blendResult.TargetHeight, blendResult.MaxBlend) - blendedHeight, -8f, 8f);
					if (Mathf.Abs(num) > 0.01f || blendResult.MaxBlend > 0.5f)
					{
						int num2 = i * context.GridSize + j;
						context.TerrainComp.m_levelDelta[num2] = num;
						context.TerrainComp.m_smoothDelta[num2] = 0f;
						context.TerrainComp.m_modifiedHeight[num2] = true;
						result.VerticesModified++;
						if (result.VerticesModified <= 3)
						{
							ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)($"[VERTEX] Zone {zoneID} v[{j},{i}]: pos=({val.x:F1},{val.z:F1}), " + $"base={blendedHeight:F2}m, target={blendResult.TargetHeight:F2}m, blend={blendResult.MaxBlend:F2}, delta={num:F2}m"));
						}
					}
				}
			}
			return result;
		}

		private static BlendResult CalculateBlendedHeight(List<RoadSpatialGrid.RoadPoint> roadPoints, Vector2 vertexPos)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			float num2 = 0f;
			float num3 = 0f;
			int num4 = 0;
			foreach (RoadSpatialGrid.RoadPoint roadPoint in roadPoints)
			{
				Vector2 val = roadPoint.p - vertexPos;
				float sqrMagnitude = ((Vector2)(ref val)).sqrMagnitude;
				float num5 = roadPoint.w * 0.5f + 2f;
				float num6 = num5 * num5;
				if (sqrMagnitude < num6)
				{
					float num7 = Mathf.Sqrt(sqrMagnitude) / num5;
					float num8 = 1f - Mathf.SmoothStep(0f, 1f, num7);
					float num9 = num8 * num8;
					num += roadPoint.h * num9;
					num2 += num9;
					num4++;
					if (num8 > num3)
					{
						num3 = num8;
					}
				}
			}
			BlendResult result = default(BlendResult);
			result.TargetHeight = ((num4 > 0) ? (num / num2) : 0f);
			result.MaxBlend = num3;
			result.InfluencingPoints = num4;
			return result;
		}

		private static void ApplyRoadPaint(List<RoadSpatialGrid.RoadPoint> roadPoints, TerrainComp terrainComp, HashSet<Vector2i> paintedCells)
		{
			//IL_0020: 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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: 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_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			Heightmap hmap = terrainComp.m_hmap;
			if ((Object)(object)hmap == (Object)null)
			{
				return;
			}
			int num = terrainComp.m_width + 1;
			Vector3 position = ((Component)hmap).transform.position;
			float scale = hmap.m_scale;
			Vector2i item = default(Vector2i);
			foreach (RoadSpatialGrid.RoadPoint roadPoint in roadPoints)
			{
				((Vector2i)(ref item))..ctor(Mathf.RoundToInt(roadPoint.p.x / 1.5f), Mathf.RoundToInt(roadPoint.p.y / 1.5f));
				if (paintedCells.Contains(item))
				{
					continue;
				}
				paintedCells.Add(item);
				Vector3 val = new Vector3(roadPoint.p.x - 0.5f, 0f, roadPoint.p.y - 0.5f) - position;
				int num2 = (terrainComp.m_width + 1) / 2;
				int num3 = Mathf.FloorToInt(val.x / scale + 0.5f) + num2;
				int num4 = Mathf.FloorToInt(val.z / scale + 0.5f) + num2;
				float num5 = roadPoint.w * 0.5f / scale;
				int num6 = Mathf.CeilToInt(num5);
				for (int i = -num6; i <= num6; i++)
				{
					for (int j = -num6; j <= num6; j++)
					{
						int num7 = num3 + j;
						int num8 = num4 + i;
						if (num7 >= 0 && num8 >= 0 && num7 < num && num8 < num)
						{
							float num9 = Mathf.Sqrt((float)(j * j + i * i));
							if (!(num9 > num5))
							{
								float num10 = 1f - Mathf.Clamp01(num9 / num5);
								num10 = Mathf.Pow(num10, 0.1f);
								int num11 = num8 * num + num7;
								Color val2 = terrainComp.m_paintMask[num11];
								float a = val2.a;
								Color val3 = Color.Lerp(val2, Heightmap.m_paintMaskPaved, num10);
								val3.a = a;
								terrainComp.m_modifiedPaint[num11] = true;
								terrainComp.m_paintMask[num11] = val3;
							}
						}
					}
				}
			}
		}

		private static void FinalizeTerrainMods(Vector2i zoneID, int roadPointCount, ModificationStats stats, TerrainContext context)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			int count = stats.PaintedCells.Count;
			if (stats.VerticesModified > 0 || count > 0)
			{
				context.TerrainComp.Save();
				context.Heightmap.Poke(true);
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"Zone {zoneID}: {stats.VerticesModified}/{stats.VerticesChecked} vertices modified, {count} paint cells");
			}
			else if (roadPointCount > 0)
			{
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogWarning((object)$"Zone {zoneID}: {roadPointCount} road points but 0 vertices matched! Coordinate mismatch?");
			}
		}

		private static void LogCoordinateDebug(Vector2i zoneID, List<RoadSpatialGrid.RoadPoint> roadPoints, TerrainContext context)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			if (s_coordLogCount < 3)
			{
				s_coordLogCount++;
				float num = (float)context.TerrainComp.m_width / 2f * context.VertexSpacing;
				RoadSpatialGrid.RoadPoint roadPoint = ((roadPoints.Count > 0) ? roadPoints[0] : default(RoadSpatialGrid.RoadPoint));
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)($"[COORD DEBUG] Zone {zoneID}: hmPos=({context.HeightmapPosition.x:F1},{context.HeightmapPosition.z:F1}), " + $"vertices cover X[{context.HeightmapPosition.x - num:F1},{context.HeightmapPosition.x + num:F1}], " + $"first road point=({roadPoint.p.x:F1},{roadPoint.p.y:F1}), width={roadPoint.w:F1}m"));
			}
		}
	}
	[BepInPlugin("warpalicious.ProceduralRoads", "ProceduralRoads", "1.1.0")]
	public class ProceduralRoadsPlugin : BaseUnityPlugin
	{
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		internal const string ModName = "ProceduralRoads";

		internal const string ModVersion = "1.1.0";

		internal const string Author = "warpalicious";

		private const string ModGUID = "warpalicious.ProceduralRoads";

		private static string ConfigFileName = "warpalicious.ProceduralRoads.cfg";

		private static string ConfigFileFullPath;

		internal static string ConnectionError;

		private readonly Harmony _harmony = new Harmony("warpalicious.ProceduralRoads");

		public static readonly ManualLogSource ProceduralRoadsLogger;

		public Texture2D tex;

		public static ConfigEntry<float> RoadWidth;

		public static ConfigEntry<string> CustomLocations;

		public static ConfigEntry<int> IslandRoadPercentage;

		public void Awake()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			RoadWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Roads", "RoadWidth", 4f, new ConfigDescription("Width of generated roads in meters", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 10f), Array.Empty<object>()));
			IslandRoadPercentage = ((BaseUnityPlugin)this).Config.Bind<int>("Roads", "IslandRoadPercentage", 50, new ConfigDescription("Percentage of islands that will have roads generated (0-100). Islands are selected by size (largest first).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			CustomLocations = ((BaseUnityPlugin)this).Config.Bind<string>("Locations", "CustomLocations", "", "Comma-separated list of location names to include in road generation. Use this for locations added by Expand World Data or other mods. Example: Runestone_Boars,Runestone_Greydwarfs,MerchantCamp");
			ApplyConfiguration();
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			_harmony.PatchAll(executingAssembly);
			SetupWatcher();
			ProceduralRoadsLogger.LogInfo((object)"ProceduralRoads v1.1.0 loaded - Procedural roads enabled");
			if (saveOnConfigSet)
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
				((BaseUnityPlugin)this).Config.Save();
			}
		}

		private static void ApplyConfiguration()
		{
			RoadNetworkGenerator.RoadWidth = RoadWidth.Value;
			RoadNetworkGenerator.IslandRoadPercentage = IslandRoadPercentage.Value;
		}

		public static HashSet<string> GetConfigLocationNames()
		{
			HashSet<string> hashSet = new HashSet<string>();
			if (string.IsNullOrWhiteSpace(CustomLocations.Value))
			{
				return hashSet;
			}
			string[] array = CustomLocations.Value.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (!string.IsNullOrEmpty(text))
				{
					hashSet.Add(text);
				}
			}
			return hashSet;
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.Save();
		}

		private void SetupWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReadConfigValues;
			fileSystemWatcher.Created += ReadConfigValues;
			fileSystemWatcher.Renamed += ReadConfigValues;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				ProceduralRoadsLogger.LogDebug((object)"ReadConfigValues called");
				((BaseUnityPlugin)this).Config.Reload();
				ApplyConfiguration();
			}
			catch
			{
				ProceduralRoadsLogger.LogError((object)("There was an issue loading your " + ConfigFileName));
				ProceduralRoadsLogger.LogError((object)"Please check your config entries for spelling and format!");
			}
		}

		static ProceduralRoadsPlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
			ConnectionError = "";
			ProceduralRoadsLogger = Logger.CreateLogSource("ProceduralRoads");
			RoadWidth = null;
			CustomLocations = null;
			IslandRoadPercentage = null;
		}
	}
	public static class KeyboardExtensions
	{
		public static bool IsKeyDown(this KeyboardShortcut shortcut)
		{
			//IL_0002: 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)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			return false;
		}

		public static bool IsKeyHeld(this KeyboardShortcut shortcut)
		{
			//IL_0002: 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)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			return false;
		}
	}
	public static class RoadConstants
	{
		public const float ZoneSize = 64f;

		public const float HalfZoneSize = 32f;

		public const float SeaLevel = 30f;

		public const float DeepWaterHeight = 28f;

		public const float ShallowWaterHeight = 30.5f;

		public const float TerrainDeltaMin = -8f;

		public const float TerrainDeltaMax = 8f;

		public const float PathfindingCellSize = 8f;

		public const int PathfindingMaxIterations = 100000;

		public const float TerrainVarianceSampleRadius = 16f;

		public const int TerrainVarianceSampleCount = 8;

		public const float MountainSlopeThreshold = 0.4f;

		public const float RiverImpassableThreshold = 0.5f;

		public const float DefaultBaseCost = 1f;

		public const float DefaultSlopeMultiplier = 10f;

		public const float DefaultRiverPenalty = 100000f;

		public const float DefaultWaterPenalty = 100000f;

		public const float DefaultSteepSlopePenalty = 2000f;

		public const float DefaultSteepSlopeThreshold = 0.6f;

		public const float DefaultTerrainVariancePenalty = 1000f;

		public const float DefaultTerrainVarianceThreshold = 5f;

		public const float SpatialGridSize = 64f;

		public const float DefaultRoadWidth = 4f;

		public const float EdgeFalloffStart = 0.6f;

		public const int HeightSmoothingWindow = 41;

		public const float OverlapThreshold = 0.3f;

		public const float OverlapSearchRadiusMultiplier = 0.6f;

		public const float OverlapBlendRadiusMultiplier = 0.8f;

		public const float TerrainBlendMargin = 2f;

		public const float PaintDedupeInterval = 1.5f;

		public const float MinHeightDeltaThreshold = 0.01f;

		public const float MinBlendForModification = 0.5f;

		public const float VegetationClearMultiplier = 0.6f;

		public const float VegetationClearSampleInterval = 4f;

		public const int MaxCoordDebugLogs = 3;

		public const int MaxVertexModificationLogs = 3;
	}
	public static class RoadNetworkGenerator
	{
		public struct LocationData
		{
			public Vector3 SpawnPoint;

			public float SpawnRadius;

			public List<(string name, Vector3 position, float radius)> BossLocations;

			public List<(string name, Vector3 position, float radius)> AllLocations;
		}

		private static readonly HashSet<string> BossLocationNames = new HashSet<string> { "Eikthyrnir", "GDKing", "Bonemass", "Dragonqueen", "GoblinKing", "SeekerQueen" };

		private static readonly Dictionary<string, int> LocationPriorities = new Dictionary<string, int>
		{
			{ "Eikthyrnir", 100 },
			{ "GDKing", 100 },
			{ "Bonemass", 100 },
			{ "Dragonqueen", 100 },
			{ "GoblinKing", 100 },
			{ "SeekerQueen", 100 },
			{ "Crypt4", 80 },
			{ "SunkenCrypt4", 80 },
			{ "MountainCave02", 80 },
			{ "TrollCave02", 40 },
			{ "Crypt3", 75 },
			{ "Mistlands_DvergrTownEntrance1", 75 },
			{ "Mistlands_DvergrTownEntrance2", 75 },
			{ "Mistlands_Harbour1", 70 },
			{ "WoodVillage1", 60 },
			{ "WoodFarm1", 55 },
			{ "Mistlands_GuardTower1_new", 50 },
			{ "Mistlands_GuardTower2_new", 50 },
			{ "Mistlands_GuardTower3_new", 50 },
			{ "Mistlands_Lighthouse1_new", 50 },
			{ "Mistlands_Excavation1", 45 },
			{ "Mistlands_Excavation2", 45 },
			{ "Mistlands_Excavation3", 45 },
			{ "StoneTower1", 40 },
			{ "StoneTower3", 40 },
			{ "Mistlands_GuardTower1_ruined_new", 30 },
			{ "Mistlands_GuardTower3_ruined_new", 30 },
			{ "StoneTowerRuins03", 30 },
			{ "StoneTowerRuins04", 30 },
			{ "StoneTowerRuins05", 30 },
			{ "StoneTowerRuins07", 30 },
			{ "StoneTowerRuins08", 30 },
			{ "StoneTowerRuins09", 30 },
			{ "StoneTowerRuins10", 30 },
			{ "StoneHenge1", 25 },
			{ "StoneHenge2", 25 },
			{ "StoneHenge3", 25 },
			{ "SwampHut5", 25 },
			{ "SwampRuin1", 25 },
			{ "SwampRuin2", 25 }
		};

		private const int DefaultPriority = 20;

		private const int MinLocationsPerIsland = 2;

		private const int MaxLocationsPerIsland = 12;

		private const float AreaPerLocation = 2000000f;

		private static readonly HashSet<string> RegisteredLocationNames = new HashSet<string>();

		public static float RoadWidth = 4f;

		public static int IslandRoadPercentage = 50;

		private static bool m_roadsGenerated = false;

		private static bool m_locationsReady = false;

		private static bool m_roadsLoadedFromZDO = false;

		private static RoadPathfinder? m_pathfinder;

		private static int m_roadsGeneratedCount = 0;

		private static List<(Vector2 position, string label)> m_roadStartPoints = new List<(Vector2, string)>();

		private const string MetadataPrefabName = "ProceduralRoads_Metadata";

		private static readonly int MetadataPrefabHash = StringExtensionMethods.GetStableHashCode("ProceduralRoads_Metadata");

		private static readonly int RoadStartPointsHash = StringExtensionMethods.GetStableHashCode("ProceduralRoads_StartPoints");

		private static ManualLogSource Log => ProceduralRoadsPlugin.ProceduralRoadsLogger;

		public static bool RoadsGenerated => m_roadsGenerated;

		public static bool IsLocationsReady => m_locationsReady;

		public static bool RoadsLoadedFromZDO => m_roadsLoadedFromZDO;

		public static bool RoadsAvailable
		{
			get
			{
				if (!m_roadsGenerated)
				{
					return m_roadsLoadedFromZDO;
				}
				return true;
			}
		}

		public static void RegisterLocation(string locationName)
		{
			if (!string.IsNullOrWhiteSpace(locationName))
			{
				string text = locationName.Trim();
				if (RegisteredLocationNames.Add(text))
				{
					Log.LogDebug((object)("Registered location for roads: " + text));
				}
			}
		}

		public static void UnregisterLocation(string locationName)
		{
			if (!string.IsNullOrWhiteSpace(locationName))
			{
				string text = locationName.Trim();
				if (RegisteredLocationNames.Remove(text))
				{
					Log.LogDebug((object)("Unregistered location from roads: " + text));
				}
			}
		}

		public static IReadOnlyCollection<string> GetRegisteredLocations()
		{
			return RegisteredLocationNames;
		}

		public static IReadOnlyList<(Vector2 position, string label)> GetRoadStartPoints()
		{
			return m_roadStartPoints;
		}

		public static void Initialize()
		{
			Reset();
		}

		public static void MarkLocationsReady()
		{
			m_locationsReady = true;
			Log.LogDebug((object)"Locations marked ready for road generation");
		}

		public static void MarkRoadsLoadedFromZDO()
		{
			m_roadsLoadedFromZDO = true;
			Log.LogDebug((object)"Roads marked as loaded from ZDO persistence");
		}

		public static void GenerateRoads(bool force = false)
		{
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			if (m_roadsGenerated && !force)
			{
				Log.LogDebug((object)"Roads already generated, skipping");
				return;
			}
			if (force && m_roadsGenerated)
			{
				Log.LogDebug((object)"Force regenerating roads...");
				Reset();
			}
			if (WorldGenerator.instance == null)
			{
				Log.LogWarning((object)"WorldGenerator not available, cannot generate roads");
				return;
			}
			if ((Object)(object)ZoneSystem.instance == (Object)null)
			{
				Log.LogWarning((object)"ZoneSystem not available, cannot generate roads");
				return;
			}
			Log.LogDebug((object)"Starting road network generation...");
			DateTime now = DateTime.Now;
			m_pathfinder = new RoadPathfinder(WorldGenerator.instance);
			m_roadsGeneratedCount = 0;
			LocationData? locationData = GatherLocationData();
			if (!locationData.HasValue)
			{
				return;
			}
			List<Island> list = IslandDetector.DetectIslands();
			List<Island> list2 = list.OrderByDescending((Island i) => i.ApproxArea).ToList();
			int num = Mathf.Max(1, Mathf.RoundToInt((float)(list2.Count * IslandRoadPercentage) / 100f));
			List<Island> list3 = list2.Take(num).ToList();
			Log.LogDebug((object)$"Islands: {list.Count} total, {num} selected ({IslandRoadPercentage}%)");
			foreach (Island item in list3)
			{
				List<(string, Vector3, float)> locationsOnIsland = GetLocationsOnIsland(item, locationData.Value.AllLocations);
				if (locationsOnIsland.Count != 0)
				{
					int maxLocationsForIsland = GetMaxLocationsForIsland(item);
					List<(string, Vector3, float)> list4 = SelectLocations(locationsOnIsland, maxLocationsForIsland);
					Log.LogDebug((object)$"Island {item.Id}: {locationsOnIsland.Count} candidates -> {list4.Count} selected (max {maxLocationsForIsland}, area {item.ApproxArea / 1000000f:F1}km²)");
					if (item.ContainsPoint(locationData.Value.SpawnPoint))
					{
						GenerateIslandRoads(item, list4, locationData.Value.SpawnPoint, locationData.Value.SpawnRadius);
					}
					else
					{
						GenerateIslandRoads(item, list4);
					}
				}
			}
			TimeSpan elapsed = DateTime.Now - now;
			LogGenerationStats(m_roadsGeneratedCount, elapsed);
			RoadSpatialGrid.FinalizeRoadNetwork();
			m_roadsGenerated = true;
			m_pathfinder = null;
		}

		public static bool GenerateRoad(Vector2 startCenter, float startRadius, Vector2 endCenter, float endRadius, float width, string? label = null)
		{
			//IL_001d: 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_0053: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			if (m_pathfinder == null)
			{
				Log.LogWarning((object)"GenerateRoad called without active pathfinder");
				return false;
			}
			List<Vector2> list = m_pathfinder.FindPath(startCenter, endCenter);
			Canvas.ForceUpdateCanvases();
			if (list == null || list.Count < 2)
			{
				if (label != null)
				{
					Log.LogWarning((object)("Could not find path: " + label));
				}
				return false;
			}
			list = TrimPathToRadii(list, startCenter, startRadius, endCenter, endRadius);
			if (list == null || list.Count < 2)
			{
				if (label != null)
				{
					Log.LogWarning((object)("Path too short after trimming: " + label));
				}
				return false;
			}
			RoadSpatialGrid.AddRoadPath(list, width, WorldGenerator.instance);
			m_roadsGeneratedCount++;
			if (list.Count > 0)
			{
				string item = label ?? $"Road {m_roadsGeneratedCount}";
				m_roadStartPoints.Add((list[0], item));
			}
			if (label != null)
			{
				Log.LogDebug((object)$"Generated road: {label} ({list.Count} waypoints)");
			}
			return true;
		}

		public static bool GenerateRoad(Vector3 startPos, float startRadius, Vector3 endPos, float endRadius, float width, string? label = null)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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)
			//IL_0018: 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)
			return RoadNetworkGenerator.GenerateRoad(new Vector2(startPos.x, startPos.z), startRadius, new Vector2(endPos.x, endPos.z), endRadius, width, label);
		}

		private static LocationData? GatherLocationData()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<Vector2i, LocationInstance>.ValueCollection locationList = ZoneSystem.instance.GetLocationList();
			if (locationList == null || locationList.Count == 0)
			{
				Log.LogWarning((object)"No location instances found");
				return null;
			}
			Vector3? val = null;
			float spawnRadius = 0f;
			List<(string, Vector3, float)> list = new List<(string, Vector3, float)>();
			List<(string, Vector3, float)> list2 = new List<(string, Vector3, float)>();
			foreach (LocationInstance item in locationList)
			{
				string name = item.m_location.m_prefab.Name;
				float exteriorRadius = item.m_location.m_exteriorRadius;
				list2.Add((name, item.m_position, exteriorRadius));
				if (name == "StartTemple")
				{
					val = item.m_position;
					spawnRadius = exteriorRadius;
				}
				else if (BossLocationNames.Contains(name))
				{
					list.Add((name, item.m_position, exteriorRadius));
				}
			}
			if (!val.HasValue)
			{
				Log.LogWarning((object)"Could not find spawn point (StartTemple)");
				val = Vector3.zero;
			}
			Log.LogDebug((object)$"Found spawn at {val.Value}, {list.Count} boss locations, {list2.Count} total locations");
			LocationData value = default(LocationData);
			value.SpawnPoint = val.Value;
			value.SpawnRadius = spawnRadius;
			value.BossLocations = list;
			value.AllLocations = list2;
			return value;
		}

		private static List<(string name, Vector3 position, float radius)> GetLocationsOnIsland(Island island, List<(string name, Vector3 position, float radius)> allLocations)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			List<(string, Vector3, float)> list = new List<(string, Vector3, float)>();
			foreach (var allLocation in allLocations)
			{
				if (island.ContainsPoint(allLocation.position) && IsRoadLocation(allLocation.name))
				{
					list.Add(allLocation);
				}
			}
			return list;
		}

		private static bool IsRoadLocation(string locationName)
		{
			if (!BossLocationNames.Contains(locationName) && !LocationPriorities.ContainsKey(locationName))
			{
				return RegisteredLocationNames.Contains(locationName);
			}
			return true;
		}

		private static int GetMaxLocationsForIsland(Island island)
		{
			return Mathf.Clamp(2 + (int)(island.ApproxArea / 2000000f), 2, 12);
		}

		private static List<(string name, Vector3 position, float radius)> SelectLocations(List<(string name, Vector3 position, float radius)> candidates, int maxCount)
		{
			if (candidates.Count <= maxCount)
			{
				return candidates;
			}
			return candidates.OrderByDescending<(string, Vector3, float), int>(((string name, Vector3 position, float radius) loc) => GetLocationPriority(loc.name)).Take(maxCount).ToList();
		}

		private static int GetLocationPriority(string locationName)
		{
			if (!LocationPriorities.TryGetValue(locationName, out var value))
			{
				return 20;
			}
			return value;
		}

		private static void GenerateChainRoads(Vector3 startPos, float startRadius, List<(string name, Vector3 position, float radius)> locations)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			if (locations.Count == 0)
			{
				return;
			}
			List<(string, Vector3, float)> list = new List<(string, Vector3, float)>(locations);
			Vector3 val = startPos;
			float startRadius2 = startRadius;
			string text = "Start";
			while (list.Count > 0)
			{
				int index = 0;
				float num = float.MaxValue;
				for (int i = 0; i < list.Count; i++)
				{
					float num2 = Vector3.Distance(val, list[i].Item2);
					if (num2 < num)
					{
						num = num2;
						index = i;
					}
				}
				(string, Vector3, float) tuple = list[index];
				list.RemoveAt(index);
				GenerateRoad(val, startRadius2, tuple.Item2, tuple.Item3, RoadWidth, text + " -> " + tuple.Item1);
				val = tuple.Item2;
				startRadius2 = tuple.Item3;
				(text, _, _) = tuple;
			}
		}

		private static void GenerateMSTRoads(Vector3 startPos, float startRadius, List<(string name, Vector3 position, float radius)> locations)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			if (locations.Count == 0)
			{
				return;
			}
			List<(string, Vector3, float)> list = new List<(string, Vector3, float)>();
			list.Add(("Start", startPos, startRadius));
			list.AddRange(locations);
			bool[] array = new bool[list.Count];
			float[] array2 = new float[list.Count];
			int[] array3 = new int[list.Count];
			for (int i = 0; i < list.Count; i++)
			{
				array2[i] = float.MaxValue;
				array3[i] = -1;
			}
			array2[0] = 0f;
			for (int j = 0; j < list.Count; j++)
			{
				int num = -1;
				for (int k = 0; k < list.Count; k++)
				{
					if (!array[k] && (num == -1 || array2[k] < array2[num]))
					{
						num = k;
					}
				}
				if (num == -1 || array2[num] == float.MaxValue)
				{
					break;
				}
				array[num] = true;
				for (int l = 0; l < list.Count; l++)
				{
					if (!array[l])
					{
						float num2 = Vector3.Distance(list[num].Item2, list[l].Item2);
						if (num2 < array2[l])
						{
							array2[l] = num2;
							array3[l] = num;
						}
					}
				}
			}
			for (int m = 1; m < list.Count; m++)
			{
				if (array3[m] >= 0)
				{
					(string, Vector3, float) tuple = list[array3[m]];
					(string, Vector3, float) tuple2 = list[m];
					GenerateRoad(tuple.Item2, tuple.Item3, tuple2.Item2, tuple2.Item3, RoadWidth, tuple.Item1 + " -> " + tuple2.Item1);
				}
			}
		}

		private static void GenerateIslandRoads(Island island, List<(string name, Vector3 position, float radius)> islandLocations, Vector3? overrideStart = null, float overrideStartRadius = 0f)
		{
			//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_0027: 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)
			//IL_0014: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			if (islandLocations.Count != 0)
			{
				Vector3 value = default(Vector3);
				float startRadius;
				if (overrideStart.HasValue)
				{
					value = overrideStart.Value;
					startRadius = overrideStartRadius;
				}
				else
				{
					Vector2 edgePoint = island.GetEdgePoint();
					((Vector3)(ref value))..ctor(edgePoint.x, 0f, edgePoint.y);
					startRadius = 0f;
				}
				bool flag = island.Id % 2 == 0;
				Log.LogDebug((object)string.Format("Island {0}: {1} locations, strategy={2}", island.Id, islandLocations.Count, flag ? "MST" : "Chain"));
				if (flag)
				{
					GenerateMSTRoads(value, startRadius, islandLocations);
				}
				else
				{
					GenerateChainRoads(value, startRadius, islandLocations);
				}
			}
		}

		public static void Reset()
		{
			m_roadsGenerated = false;
			m_locationsReady = false;
			m_roadsLoadedFromZDO = false;
			m_pathfinder = null;
			m_roadsGeneratedCount = 0;
			m_roadStartPoints.Clear();
			RoadSpatialGrid.Clear();
		}

		private static void LogGenerationStats(int roadsGenerated, TimeSpan elapsed)
		{
			ManualLogSource log = Log;
			log.LogDebug((object)"=== Road Generation Summary ===");
			log.LogDebug((object)$"  Roads generated: {roadsGenerated}");
			log.LogDebug((object)$"  Total road points: {RoadSpatialGrid.TotalRoadPoints}");
			log.LogDebug((object)$"  Total road length: {RoadSpatialGrid.TotalRoadLength:F0}m");
			log.LogDebug((object)$"  Grid cells with roads: {RoadSpatialGrid.GridCellsWithRoads}");
			if (roadsGenerated > 0)
			{
				log.LogDebug((object)$"  Avg points/road: {(float)RoadSpatialGrid.TotalRoadPoints / (float)roadsGenerated:F0}");
				log.LogDebug((object)$"  Avg length/road: {RoadSpatialGrid.TotalRoadLength / (float)roadsGenerated:F0}m");
			}
			log.LogDebug((object)$"  Generation time: {elapsed.TotalSeconds:F2}s");
			log.LogDebug((object)$"  Road width: {RoadWidth}m");
			log.LogDebug((object)"===============================");
		}

		private static List<Vector2>? TrimPathToRadii(List<Vector2> path, Vector2 startCenter, float startRadius, Vector2 endCenter, float endRadius)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00b5: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			if (path == null || path.Count < 2)
			{
				return null;
			}
			int num = 0;
			float num2 = startRadius * startRadius;
			Vector2 val;
			for (int i = 0; i < path.Count; i++)
			{
				val = path[i] - startCenter;
				if (((Vector2)(ref val)).sqrMagnitude > num2)
				{
					num = i;
					break;
				}
			}
			int num3 = path.Count - 1;
			float num4 = endRadius * endRadius;
			for (int num5 = path.Count - 1; num5 >= 0; num5--)
			{
				val = path[num5] - endCenter;
				if (((Vector2)(ref val)).sqrMagnitude > num4)
				{
					num3 = num5;
					break;
				}
			}
			if (num3 <= num)
			{
				return null;
			}
			List<Vector2> list = new List<Vector2>();
			if (num > 0 && num < path.Count)
			{
				Vector2 item = CalculateRadiusIntersection(path[num], startCenter, startRadius);
				list.Add(item);
			}
			for (int j = num; j <= num3; j++)
			{
				list.Add(path[j]);
			}
			if (num3 < path.Count - 1 && num3 >= 0)
			{
				Vector2 item2 = CalculateRadiusIntersection(path[num3], endCenter, endRadius);
				list.Add(item2);
			}
			if (list.Count < 2)
			{
				return null;
			}
			return list;
		}

		private static Vector2 CalculateRadiusIntersection(Vector2 outsidePoint, Vector2 center, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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)
			Vector2 val = outsidePoint - center;
			Vector2 normalized = ((Vector2)(ref val)).normalized;
			return center + normalized * radius;
		}

		public static void SaveRoadMetadata()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if (m_roadStartPoints.Count == 0)
			{
				Log.LogDebug((object)"No road start points to save");
				return;
			}
			if (ZDOMan.instance == null)
			{
				Log.LogWarning((object)"ZDOMan not available, cannot save road metadata");
				return;
			}
			ZDO val = FindMetadataZDO();
			if (val == null)
			{
				val = ZDOMan.instance.CreateNewZDO(Vector3.zero, MetadataPrefabHash);
				Log.LogDebug((object)$"Created new metadata ZDO: {val.m_uid}");
			}
			else
			{
				Log.LogDebug((object)$"Found existing metadata ZDO: {val.m_uid}");
			}
			byte[] array = SerializeRoadStartPoints();
			if (array != null && array.Length != 0)
			{
				val.Set(RoadStartPointsHash, array);
				Log.LogDebug((object)$"Saved {m_roadStartPoints.Count} road start points ({array.Length} bytes)");
			}
		}

		public static bool TryLoadRoadMetadata()
		{
			if (ZDOMan.instance == null)
			{
				return false;
			}
			ZDO val = FindMetadataZDO();
			if (val == null)
			{
				Log.LogDebug((object)"No road metadata ZDO found");
				return false;
			}
			byte[] byteArray = val.GetByteArray(RoadStartPointsHash, (byte[])null);
			if (byteArray == null || byteArray.Length == 0)
			{
				Log.LogDebug((object)"Metadata ZDO found but no start points data");
				return false;
			}
			if (DeserializeRoadStartPoints(byteArray))
			{
				Log.LogDebug((object)$"Loaded {m_roadStartPoints.Count} road start points from ZDO");
				return true;
			}
			return false;
		}

		private static ZDO? FindMetadataZDO()
		{
			if (ZDOMan.instance == null)
			{
				return null;
			}
			List<ZDO> list = new List<ZDO>();
			int num = 0;
			while (ZDOMan.instance.GetAllZDOsWithPrefabIterative("ProceduralRoads_Metadata", list, ref num))
			{
			}
			if (list.Count > 0)
			{
				return list[0];
			}
			return null;
		}

		private static byte[] SerializeRoadStartPoints()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write(m_roadStartPoints.Count);
			foreach (var (val, text) in m_roadStartPoints)
			{
				binaryWriter.Write(val.x);
				binaryWriter.Write(val.y);
				byte[] bytes = Encoding.UTF8.GetBytes(text ?? "");
				binaryWriter.Write(bytes.Length);
				binaryWriter.Write(bytes);
			}
			return memoryStream.ToArray();
		}

		private static bool DeserializeRoadStartPoints(byte[] data)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				using MemoryStream input = new MemoryStream(data);
				using BinaryReader binaryReader = new BinaryReader(input);
				int num = binaryReader.ReadInt32();
				if (num < 0 || num > 10000)
				{
					Log.LogWarning((object)$"Invalid road start points count: {num}");
					return false;
				}
				m_roadStartPoints.Clear();
				for (int i = 0; i < num; i++)
				{
					float num2 = binaryReader.ReadSingle();
					float num3 = binaryReader.ReadSingle();
					int num4 = binaryReader.ReadInt32();
					if (num4 < 0 || num4 > 1000)
					{
						Log.LogWarning((object)$"Invalid label length: {num4}");
						return false;
					}
					byte[] bytes = binaryReader.ReadBytes(num4);
					string @string = Encoding.UTF8.GetString(bytes);
					m_roadStartPoints.Add((new Vector2(num2, num3), @string));
				}
				return true;
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Failed to deserialize road start points: " + ex.Message));
				return false;
			}
		}
	}
	public class RoadPathfinder
	{
		public const float CellSize = 8f;

		public const int MaxIterations = 100000;

		public float SlopeMultiplier = 10f;

		public float RiverPenalty = 100000f;

		public float WaterPenalty = 100000f;

		public float SteepSlopePenalty = 2000f;

		public float SteepSlopeThreshold = 0.6f;

		public float TerrainVariancePenalty = 1000f;

		public float TerrainVarianceThreshold = 5f;

		public float BaseCost = 1f;

		private static readonly Vector2Int[] Directions;

		private static readonly float[] DirectionCosts;

		private WorldGenerator m_worldGen;

		private static ManualLogSource Log => ProceduralRoadsPlugin.ProceduralRoadsLogger;

		static RoadPathfinder()
		{
			//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_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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			Directions = (Vector2Int[])(object)new Vector2Int[16]
			{
				new Vector2Int(1, 0),
				new Vector2Int(-1, 0),
				new Vector2Int(0, 1),
				new Vector2Int(0, -1),
				new Vector2Int(1, 1),
				new Vector2Int(-1, 1),
				new Vector2Int(1, -1),
				new Vector2Int(-1, -1),
				new Vector2Int(2, 1),
				new Vector2Int(2, -1),
				new Vector2Int(-2, 1),
				new Vector2Int(-2, -1),
				new Vector2Int(1, 2),
				new Vector2Int(-1, 2),
				new Vector2Int(1, -2),
				new Vector2Int(-1, -2)
			};
			DirectionCosts = new float[Directions.Length];
			for (int i = 0; i < Directions.Length; i++)
			{
				DirectionCosts[i] = Mathf.Sqrt((float)(((Vector2Int)(ref Directions[i])).x * ((Vector2Int)(ref Directions[i])).x + ((Vector2Int)(ref Directions[i])).y * ((Vector2Int)(ref Directions[i])).y));
			}
		}

		public RoadPathfinder(WorldGenerator worldGen)
		{
			m_worldGen = worldGen;
		}

		public List<Vector2> FindPath(Vector2 start, Vector2 end)
		{
			//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)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0026: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_00ad: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: 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_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: 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_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			Vector2i val = WorldToGrid(start);
			Vector2i val2 = WorldToGrid(end);
			if (val == val2)
			{
				return new List<Vector2> { start, end };
			}
			SortedSet<(float, Vector2i)> sortedSet = new SortedSet<(float, Vector2i)>(Comparer<(float, Vector2i)>.Create(delegate((float priority, Vector2i pos) a, (float priority, Vector2i pos) b)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				int num4 = a.priority.CompareTo(b.priority);
				if (num4 != 0)
				{
					return num4;
				}
				num4 = a.pos.x.CompareTo(b.pos.x);
				return (num4 != 0) ? num4 : a.pos.y.CompareTo(b.pos.y);
			}));
			Dictionary<Vector2i, float> dictionary = new Dictionary<Vector2i, float>();
			Dictionary<Vector2i, Vector2i> dictionary2 = new Dictionary<Vector2i, Vector2i>();
			HashSet<Vector2i> hashSet = new HashSet<Vector2i>();
			sortedSet.Add((Heuristic(val, val2), val));
			dictionary[val] = 0f;
			int num = 0;
			Vector2i val3 = default(Vector2i);
			while (sortedSet.Count > 0 && num < 100000)
			{
				num++;
				(float, Vector2i) min = sortedSet.Min;
				sortedSet.Remove(min);
				Vector2i item = min.Item2;
				if (item == val2)
				{
					return ReconstructPath(dictionary2, item, start, end);
				}
				hashSet.Add(item);
				for (int i = 0; i < Directions.Length; i++)
				{
					((Vector2i)(ref val3))..ctor(item.x + ((Vector2Int)(ref Directions[i])).x, item.y + ((Vector2Int)(ref Directions[i])).y);
					if (hashSet.Contains(val3))
					{
						continue;
					}
					float moveCost = GetMoveCost(item, val3, i);
					if (!(moveCost >= RiverPenalty))
					{
						float num2 = dictionary[item] + moveCost;
						if (!dictionary.TryGetValue(val3, out var value) || num2 < value)
						{
							dictionary2[val3] = item;
							dictionary[val3] = num2;
							float num3 = Heuristic(val3, val2);
							sortedSet.Remove((value + num3, val3));
							sortedSet.Add((num2 + num3, val3));
						}
					}
				}
			}
			string arg = ((sortedSet.Count == 0) ? "no reachable path" : "max iterations reached");
			Log.LogWarning((object)$"Pathfinding failed: {arg} after {num} iterations");
			return null;
		}

		private Vector2i WorldToGrid(Vector2 world)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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)
			return new Vector2i(Mathf.RoundToInt(world.x / 8f), Mathf.RoundToInt(world.y / 8f));
		}

		private Vector2 GridToWorld(Vector2i grid)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2((float)grid.x * 8f, (float)grid.y * 8f);
		}

		private float Heuristic(Vector2i from, Vector2i to)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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)
			float num = (float)(to.x - from.x) * 8f;
			float num2 = (float)(to.y - from.y) * 8f;
			return Mathf.Sqrt(num * num + num2 * num2);
		}

		private float GetTerrainVariance(Vector2 pos)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			float num;
			float num2 = (num = m_worldGen.GetHeight(pos.x, pos.y));
			for (int i = 0; i < 8; i++)
			{
				float num3 = (float)i * (float)Math.PI * 2f / 8f;
				float height = m_worldGen.GetHeight(pos.x + Mathf.Cos(num3) * 16f, pos.y + Mathf.Sin(num3) * 16f);
				num = Mathf.Min(num, height);
				num2 = Mathf.Max(num2, height);
			}
			return num2 - num;
		}

		private float GetMoveCost(Vector2i from, Vector2i to, int directionIndex)
		{
			//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)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: 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_0024: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Invalid comparison between Unknown and I4
			Vector2 val = GridToWorld(from);
			Vector2 val2 = GridToWorld(to);
			float num = DirectionCosts[directionIndex] * 8f;
			float height = m_worldGen.GetHeight(val.x, val.y);
			float num2 = Mathf.Abs(m_worldGen.GetHeight(val2.x, val2.y) - height) / num;
			float num3 = default(float);
			float num4 = default(float);
			m_worldGen.GetRiverWeight(val2.x, val2.y, ref num3, ref num4);
			if (num3 > 0.5f)
			{
				return RiverPenalty;
			}
			float height2 = m_worldGen.GetHeight(val2.x, val2.y);
			if (height2 < 28f)
			{
				return WaterPenalty * 2f;
			}
			if (height2 < 30.5f)
			{
				return WaterPenalty;
			}
			if (num2 > SteepSlopeThreshold)
			{
				return SteepSlopePenalty;
			}
			if (GetTerrainVariance(val2) > TerrainVarianceThreshold)
			{
				return TerrainVariancePenalty;
			}
			if ((int)m_worldGen.GetBiome(val2.x, val2.y, 0.02f, false) == 4 && num2 > 0.4f)
			{
				return WaterPenalty;
			}
			float num5 = ((num3 > 0f) ? (WaterPenalty * num3) : 0f);
			return BaseCost * num + num2 * num2 * SlopeMultiplier + num5;
		}

		private List<Vector2> ReconstructPath(Dictionary<Vector2i, Vector2i> cameFrom, Vector2i current, Vector2 start, Vector2 end)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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)
			//IL_0013: 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_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_0030: Unknown result type (might be due to invalid IL or missing references)
			List<Vector2> list = new List<Vector2> { end };
			while (cameFrom.ContainsKey(current))
			{
				list.Add(GridToWorld(current));
				current = cameFrom[current];
			}
			list.Add(start);
			list.Reverse();
			return list;
		}
	}
	public static class RoadSpatialGrid
	{
		public struct RoadPoint
		{
			public Vector2 p;

			public float w;

			public float w2;

			public float h;

			public RoadPoint(Vector2 position, float width, float height)
			{
				//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)
				p = position;
				w = width;
				w2 = width * width;
				h = height;
			}
		}

		public struct RoadPointDebugInfo
		{
			public int PointIndex;

			public int TotalPoints;

			public float OriginalHeight;

			public float SmoothedHeight;

			public int WindowStart;

			public int WindowEnd;

			public int ActualWindowSize;

			public float[] WindowHeights;
		}

		public const float GridSize = 64f;

		public const float DefaultRoadWidth = 4f;

		private static Dictionary<Vector2i, RoadPoint[]> m_roadPoints = new Dictionary<Vector2i, RoadPoint[]>();

		private static RoadPoint[]? m_cachedRoadPoints;

		private static Vector2i m_cachedRoadGrid = new Vector2i(-999999, -999999);

		private static ReaderWriterLockSlim m_roadCacheLock = new ReaderWriterLockSlim();

		private static bool m_initialized = false;

		private static Dictionary<Vector2, RoadPointDebugInfo> m_debugInfo = new Dictionary<Vector2, RoadPointDebugInfo>();

		public static readonly int RoadDataHash = StringExtensionMethods.GetStableHashCode("ProceduralRoads_RoadData");

		public static int TotalRoadPoints { get; private set; } = 0;


		public static int GridCellsWithRoads { get; private set; } = 0;


		public static float TotalRoadLength { get; private set; } = 0f;


		public static int RoadNetworkVersion { get; private set; } = 0;


		private static ManualLogSource Log => ProceduralRoadsPlugin.ProceduralRoadsLogger;

		public static bool IsInitialized => m_initialized;

		public static void Clear()
		{
			//IL_0024: 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)
			m_roadCacheLock.EnterWriteLock();
			try
			{
				m_roadPoints.Clear();
				m_cachedRoadPoints = null;
				m_cachedRoadGrid = new Vector2i(-999999, -999999);
				m_initialized = false;
				TotalRoadPoints = 0;
				GridCellsWithRoads = 0;
				TotalRoadLength = 0f;
				RoadNetworkVersion = 0;
				m_debugInfo.Clear();
			}
			finally
			{
				m_roadCacheLock.ExitWriteLock();
			}
		}

		public static bool TryGetDebugInfo(Vector2 position, out RoadPointDebugInfo debugInfo)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return m_debugInfo.TryGetValue(position, out debugInfo);
		}

		public static void AddRoadPath(List<Vector2> path, float width, WorldGenerator worldGen)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			if (path == null || path.Count < 2 || worldGen == null)
			{
				return;
			}
			float segmentLength = width / 4f;
			float num = 0f;
			for (int i = 0; i < path.Count - 1; i++)
			{
				num += Vector2.Distance(path[i], path[i + 1]);
			}
			List<Vector2> list = SplinePath(path, segmentLength);
			List<float> list2 = new List<float>(list.Count);
			foreach (Vector2 item in list)
			{
				list2.Add(BiomeBlendedHeight.GetBlendedHeight(item.x, item.y, worldGen));
			}
			List<RoadPointDebugInfo> debugInfos;
			List<float> list3 = SmoothHeights(list2, 41, out debugInfos);
			int num2 = DetectOverlap(list, width);
			if ((float)num2 > (float)list.Count * 0.3f)
			{
				Log.LogDebug((object)$"Road path overlaps with existing roads ({num2}/{list.Count} points), blending heights");
				BlendWithExistingRoads(list, list3, width);
			}
			Log.LogDebug((object)$"Road path: {path.Count} waypoints -> {list.Count} dense points");
			Log.LogDebug((object)$"  Path length: {num:F0}m, smoothing window: {41} points");
			Log.LogDebug((object)$"  Overlap: {num2}/{list.Count} points overlap existing roads");
			Dictionary<Vector2i, List<RoadPoint>> dictionary = new Dictionary<Vector2i, List<RoadPoint>>();
			for (int j = 0; j < list.Count; j++)
			{
				AddRoadPoint(dictionary, list[j], width, list3[j]);
				m_debugInfo[list[j]] = debugInfos[j];
			}
			MergePoints(dictionary);
			TotalRoadPoints += list.Count;
			TotalRoadLength += num;
			m_initialized = true;
		}

		public static void FinalizeRoadNetwork()
		{
			WorldGenerator instance = WorldGenerator.instance;
			RoadNetworkVersion = ((((instance != null) ? instance.GetSeed() : 0) * 31 + TotalRoadPoints) * 31 + GridCellsWithRoads) * 31 + (int)(TotalRoadLength * 10f);
			Log.LogDebug((object)$"Road network finalized: version={RoadNetworkVersion}, points={TotalRoadPoints}, cells={GridCellsWithRoads}");
		}

		private static Vector2 CatmullRom(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_002e: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_0053: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			float num = t * t;
			float num2 = num * t;
			return 0.5f * (2f * p1 + (-p0 + p2) * t + (2f * p0 - 5f * p1 + 4f * p2 - p3) * num + (-p0 + 3f * p1 - 3f * p2 + p3) * num2);
		}

		private static List<Vector2> SplinePath(List<Vector2> waypoints, float segmentLength)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if (waypoints.Count < 2)
			{
				return new List<Vector2>(waypoints);
			}
			List<Vector2> list = new List<Vector2>();
			for (int i = 0; i < waypoints.Count - 1; i++)
			{
				Vector2 p = waypoints[Mathf.Max(0, i - 1)];
				Vector2 val = waypoints[i];
				Vector2 val2 = waypoints[i + 1];
				Vector2 p2 = waypoints[Mathf.Min(waypoints.Count - 1, i + 2)];
				float num = Vector2.Distance(val, val2);
				int num2 = Mathf.Max(1, Mathf.CeilToInt(num / segmentLength));
				for (int j = 0; j < num2; j++)
				{
					float t = (float)j / (float)num2;
					list.Add(CatmullRom(p, val, val2, p2, t));
				}
			}
			list.Add(waypoints[waypoints.Count - 1]);
			return list;
		}

		private static List<float> SmoothHeights(List<float> heights, int windowSize, out List<RoadPointDebugInfo> debugInfos)
		{
			debugInfos = new List<RoadPointDebugInfo>(heights.Count);
			if (heights.Count < 2)
			{
				if (heights.Count == 1)
				{
					debugInfos.Add(new RoadPointDebugInfo
					{
						PointIndex = 0,
						TotalPoints = 1,
						OriginalHeight = heights[0],
						SmoothedHeight = heights[0],
						ActualWindowSize = 1
					});
				}
				return new List<float>(heights);
			}
			List<float> list = new List<float>(heights.Count);
			int num = windowSize / 2;
			for (int i = 0; i < heights.Count; i++)
			{
				float num2 = 0f;
				int num3 = 0;
				int num4 = Mathf.Max(0, i - num);
				int num5 = Mathf.Min(heights.Count - 1, i + num);
				List<float> list2 = new List<float>();
				for (int j = num4; j <= num5; j++)
				{
					num2 += heights[j];
					num3++;
					list2.Add(heights[j]);
				}
				float num6 = num2 / (float)num3;
				list.Add(num6);
				debugInfos.Add(new RoadPointDebugInfo
				{
					PointIndex = i,
					TotalPoints = heights.Count,
					OriginalHeight = heights[i],
					SmoothedHeight = num6,
					WindowStart = num4,
					WindowEnd = num5,
					ActualWindowSize = num3,
					WindowHeights = list2.ToArray()
				});
			}
			return list;
		}

		private static int DetectOverlap(List<Vector2> points, float width)
		{
			//IL_002a: 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)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (!m_initialized || m_roadPoints.Count == 0)
			{
				return 0;
			}
			int num = 0;
			float num2 = width * 0.6f;
			foreach (Vector2 point in points)
			{
				Vector2i roadGrid = GetRoadGrid(point.x, point.y);
				m_roadCacheLock.EnterReadLock();
				try
				{
					if (!m_roadPoints.TryGetValue(roadGrid, out RoadPoint[] value))
					{
						continue;
					}
					RoadPoint[] array = value;
					for (int i = 0; i < array.Length; i++)
					{
						if (Vector2.Distance(array[i].p, point) < num2)
						{
							num++;
							break;
						}
					}
				}
				finally
				{
					m_roadCacheLock.ExitReadLock();
				}
			}
			return num;
		}

		private static void BlendWithExistingRoads(List<Vector2> points, List<float> heights, float width)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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)
			if (!m_initialized || m_roadPoints.Count == 0)
			{
				return;
			}
			float num = width * 0.8f;
			for (int i = 0; i < points.Count; i++)
			{
				Vector2i roadGrid = GetRoadGrid(points[i].x, points[i].y);
				m_roadCacheLock.EnterReadLock();
				try
				{
					if (!m_roadPoints.TryGetValue(roadGrid, out RoadPoint[] value))
					{
						continue;
					}
					float num2 = 1f;
					float num3 = heights[i];
					RoadPoint[] array = value;
					for (int j = 0; j < array.Length; j++)
					{
						RoadPoint roadPoint = array[j];
						float num4 = Vector2.Distance(roadPoint.p, points[i]);
						if (num4 < num)
						{
							float num5 = 1f - num4 / num;
							num3 += roadPoint.h * num5;
							num2 += num5;
						}
					}
					if (num2 > 1f)
					{
						heights[i] = num3 / num2;
					}
				}
				finally
				{
					m_roadCacheLock.ExitReadLock();
				}
			}
		}

		private static void AddRoadPoint(Dictionary<Vector2i, List<RoadPoint>> roadPoints, Vector2 p, float width, float height)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0089: 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_007a: 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_0040: 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_0068: 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)
			Vector2i roadGrid = GetRoadGrid(p.x, p.y);
			int num = Mathf.CeilToInt(width / 64f);
			Vector2i val = default(Vector2i);
			for (int i = roadGrid.y - num; i <= roadGrid.y + num; i++)
			{
				for (int j = roadGrid.x - num; j <= roadGrid.x + num; j++)
				{
					((Vector2i)(ref val))..ctor(j, i);
					if (InsideRoadGrid(val, p, width))
					{
						if (!roadPoints.TryGetValue(val, out List<RoadPoint> value))
						{
							value = new List<RoadPoint>();
							roadPoints.Add(val, value);
						}
						value.Add(new RoadPoint(p, width, height));
					}
				}
			}
		}

		private static bool InsideRoadGrid(Vector2i grid, Vector2 p, float r)
		{
			//IL_0002: 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_0021: 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_0023: 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)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor((float)grid.x * 64f, (float)grid.y * 64f);
			Vector2 val2 = p - val;
			float num = 32f;
			if (Mathf.Abs(val2.x) < r + num)
			{
				return Mathf.Abs(val2.y) < r + num;
			}
			return false;
		}

		private static void MergePoints(Dictionary<Vector2i, List<RoadPoint>> tempPoints)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			m_roadCacheLock.EnterWriteLock();
			try
			{
				foreach (KeyValuePair<Vector2i, List<RoadPoint>> tempPoint in tempPoints)
				{
					if (m_roadPoints.TryGetValue(tempPoint.Key, out RoadPoint[] value))
					{
						List<RoadPoint> list = new List<RoadPoint>(value);
						list.AddRange(tempPoint.Value);
						m_roadPoints[tempPoint.Key] = list.ToArray();
					}
					else
					{
						m_roadPoints.Add(tempPoint.Key, tempPoint.Value.ToArray());
					}
				}
				GridCellsWithRoads = m_roadPoints.Count;
				m_cachedRoadGrid = new Vector2i(-999999, -999999);
				m_cachedRoadPoints = null;
			}
			finally
			{
				m_roadCacheLock.ExitWriteLock();
			}
		}

		public static Vector2i GetRoadGrid(float wx, float wy)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.FloorToInt((wx + 32f) / 64f);
			int num2 = Mathf.FloorToInt((wy + 32f) / 64f);
			return new Vector2i(num, num2);
		}

		public static void GetRoadWeight(float wx, float wy, out float weight, out float width)
		{
			//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_