Decompiled source of Procedural Roads v1.4.2

ProceduralRoads.dll

Decompiled 10 hours ago
using System;
using System.Collections;
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 Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[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.4.2")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.2.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 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 class RoadPointDebugMarker : MonoBehaviour, Interactable, Hoverable
	{
		public 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:  ");
					int num6 = DebugInfo.WindowHeights.Length - num5;
					for (int j = num6; 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 Game_Patch
	{
		[HarmonyPatch(typeof(Game), "SpawnPlayer")]
		public static class Game_SpawnPlayer_Patch
		{
			[HarmonyPostfix]
			public static void Postfix(Vector3 spawnPoint)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				RoadLifecycleManager.OnPlayerSpawn(spawnPoint);
			}
		}
	}
	public static class ZDOMan_Patch
	{
		[HarmonyPatch(typeof(ZDOMan), "PrepareSave")]
		public static class ZDOMan_PrepareSave_Patch
		{
			[HarmonyPrefix]
			public static void Prefix()
			{
				RoadLifecycleManager.OnPrepareSave();
			}
		}
	}
	public static class ZoneSystem_Patch
	{
		[HarmonyPatch(typeof(ZoneSystem), "Start")]
		public static class ZoneSystem_Start_Patch
		{
			[HarmonyPostfix]
			public static void Postfix(ZoneSystem __instance)
			{
				RoadLifecycleManager.OnZoneSystemStart(__instance);
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "PlaceVegetation")]
		public static class ZoneSystem_PlaceVegetation_Patch
		{
			[HarmonyPrefix]
			public static void Prefix(Vector2i zoneID, List<ClearArea> clearAreas)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				if (RoadNetworkGenerator.RoadsGenerated)
				{
					List<ClearArea> orCreateClearAreas = RoadClearAreaManager.GetOrCreateClearAreas(zoneID);
					clearAreas.AddRange(orCreateClearAreas);
				}
			}
		}

		[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_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0003: Invalid comparison between Unknown and I4
				//IL_001c: 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)
				if ((int)mode != 1 && __result && RoadNetworkGenerator.RoadsGenerated)
				{
					List<RoadSpatialGrid.RoadPoint> roadPointsInZone = RoadSpatialGrid.GetRoadPointsInZone(zoneID);
					if (roadPointsInZone.Count > 0)
					{
						RoadTerrainModifier.ApplyRoadTerrainMods(zoneID, roadPointsInZone);
					}
				}
			}
		}

		[HarmonyPatch(typeof(ZoneSystem), "OnDestroy")]
		public static class ZoneSystem_OnDestroy_Patch
		{
			[HarmonyPrefix]
			public static void Prefix(ZoneSystem __instance)
			{
				RoadLifecycleManager.OnZoneSystemDestroy(__instance);
			}
		}
	}
	[BepInPlugin("warpalicious.ProceduralRoads", "ProceduralRoads", "1.4.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class ProceduralRoadsPlugin : BaseUnityPlugin
	{
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		internal const string ModName = "ProceduralRoads";

		internal const string ModVersion = "1.4.2";

		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 = null;

		public static ConfigEntry<float> RoadWidth;

		public static ConfigEntry<string> CustomLocations;

		public static ConfigEntry<int> IslandRoadPercentage;

		public static ConfigEntry<int> PathfindingMaxIterations;

		public void Awake()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			RegisterMetadataPrefab();
			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>()));
			PathfindingMaxIterations = ((BaseUnityPlugin)this).Config.Bind<int>("Roads", "PathfindingMaxIterations", 10000, new ConfigDescription("Maximum number of iterations for each road segment's pathfinding algorithm. Higher values will generate more roads but increase generation time. Lower values will speed up generation time but cause less roads to generate.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1000, 100000), 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();
			Analytics.Init(((BaseUnityPlugin)this).Config, "warpalicious.ProceduralRoads", "1.4.2");
			if (saveOnConfigSet)
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
				((BaseUnityPlugin)this).Config.Save();
			}
		}

		private void RegisterMetadataPrefab()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			GameObject val = new GameObject("ProceduralRoads_Metadata");
			ZNetView val2 = val.AddComponent<ZNetView>();
			val2.m_persistent = true;
			CustomPrefab val3 = new CustomPrefab(val, false);
			PrefabManager.Instance.AddPrefab(val3);
			ProceduralRoadsLogger.LogDebug((object)"Registered metadata prefab: ProceduralRoads_Metadata");
		}

		private static void ApplyConfiguration()
		{
			RoadNetworkGenerator.RoadWidth = RoadWidth.Value;
			RoadNetworkGenerator.IslandRoadPercentage = IslandRoadPercentage.Value;
			RoadPathfinder.MaxIterations = PathfindingMaxIterations.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] { ',' });
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = text.Trim();
				if (!string.IsNullOrEmpty(text2))
				{
					hashSet.Add(text2);
				}
			}
			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;
			PathfindingMaxIterations = null;
		}
	}
	public static class KeyboardExtensions
	{
		public static bool IsKeyDown(this KeyboardShortcut shortcut)
		{
			//IL_0003: 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)
			return (int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey) && ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
		}

		public static bool IsKeyHeld(this KeyboardShortcut shortcut)
		{
			//IL_0003: 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)
			return (int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey) && ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
		}
	}
	public static class RoadClearAreaManager
	{
		private static readonly Dictionary<Vector2i, List<ClearArea>> s_roadClearAreasCache = new Dictionary<Vector2i, List<ClearArea>>();

		public static void ClearCache()
		{
			s_roadClearAreasCache.Clear();
		}

		public static List<ClearArea> GetOrCreateClearAreas(Vector2i zoneID)
		{
			//IL_0006: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			if (!s_roadClearAreasCache.TryGetValue(zoneID, out List<ClearArea> value))
			{
				value = CreateRoadClearAreas(zoneID);
				s_roadClearAreasCache[zoneID] = value;
			}
			return value;
		}

		private static List<ClearArea> CreateRoadClearAreas(Vector2i zoneID)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_0077: 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)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: 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;
		}
	}
	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 = 10000;

		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 RoadLifecycleManager
	{
		public static void OnZoneSystemStart(ZoneSystem zoneSystem)
		{
			RoadNetworkGenerator.Initialize();
			zoneSystem.GenerateLocationsCompleted += OnLocationsGenerated;
			ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)"Subscribed to GenerateLocationsCompleted event");
		}

		public static void OnZoneSystemDestroy(ZoneSystem zoneSystem)
		{
			zoneSystem.GenerateLocationsCompleted -= OnLocationsGenerated;
			RoadNetworkGenerator.Reset();
			RoadClearAreaManager.ClearCache();
			RoadTerrainModifier.ResetDebugCounters();
			ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)"Road data cleared on world unload");
		}

		private static void OnLocationsGenerated()
		{
			ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)"Location generation complete...");
			RoadNetworkGenerator.MarkLocationsReady();
			RoadClearAreaManager.ClearCache();
			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)...");
				if (RoadNetworkGenerator.TryLoadGlobalRoadData())
				{
					RoadNetworkGenerator.MarkRoadsLoadedFromZDO();
					ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)"Loaded roads from global persistence");
				}
				else
				{
					ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)"No persisted roads found, generating...");
					RoadNetworkGenerator.GenerateRoads();
				}
			}
			else
			{
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"Deferring road generation (WorldGen={flag}, Locations={flag2})...");
			}
		}

		public static void OnPlayerSpawn(Vector3 spawnPoint)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (RoadNetworkGenerator.IsLocationsReady && !RoadNetworkGenerator.RoadsAvailable)
			{
				ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)$"Player spawning at {spawnPoint}, attempting to load global road data...");
				if (RoadNetworkGenerator.TryLoadGlobalRoadData())
				{
					RoadNetworkGenerator.MarkRoadsLoadedFromZDO();
					ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)"Roads loaded from global persistence");
				}
				else
				{
					ProceduralRoadsPlugin.ProceduralRoadsLogger.LogDebug((object)"No global road data, generating...");
					RoadNetworkGenerator.GenerateRoads();
				}
			}
		}

		public static void OnPrepareSave()
		{
			if (RoadNetworkGenerator.RoadsGenerated)
			{
				RoadNetworkGenerator.SaveGlobalRoadData();
			}
		}
	}
	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)>();

		public const string MetadataPrefabName = "ProceduralRoads_Metadata";

		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 => m_roadsGenerated || m_roadsLoadedFromZDO;

		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_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: 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...");
			HashSet<string> configLocationNames = ProceduralRoadsPlugin.GetConfigLocationNames();
			foreach (string item in configLocationNames)
			{
				if (RegisteredLocationNames.Add(item))
				{
					Log.LogDebug((object)("Added config location: " + item));
				}
			}
			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 item2 in list3)
			{
				List<(string, Vector3, float)> locationsOnIsland = GetLocationsOnIsland(item2, locationData.Value.AllLocations);
				if (locationsOnIsland.Count != 0)
				{
					int maxLocationsForIsland = GetMaxLocationsForIsland(item2);
					List<(string, Vector3, float)> list4 = SelectLocations(locationsOnIsland, maxLocationsForIsland);
					Log.LogDebug((object)$"Island {item2.Id}: {locationsOnIsland.Count} candidates -> {list4.Count} selected (max {maxLocationsForIsland}, area {item2.ApproxArea / 1000000f:F1}km²)");
					if (item2.ContainsPoint(locationData.Value.SpawnPoint))
					{
						GenerateIslandRoads(item2, list4, locationData.Value.SpawnPoint, locationData.Value.SpawnRadius);
					}
					else
					{
						GenerateIslandRoads(item2, list4);
					}
				}
			}
			TimeSpan elapsed = DateTime.Now - now;
			LogGenerationStats(m_roadsGeneratedCount, elapsed);
			RoadSpatialGrid.FinalizeRoadNetwork();
			m_roadsGenerated = true;
			m_pathfinder = null;
			RoadNetworkPersistence.EnsureMetadataInstance();
		}

		public static bool GenerateRoad(Vector2 startCenter, float startRadius, Vector2 endCenter, float endRadius, float width, string? label = null)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_0001: 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_000d: 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_0019: 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)
			return RoadNetworkGenerator.GenerateRoad(new Vector2(startPos.x, startPos.z), startRadius, new Vector2(endPos.x, endPos.z), endRadius, width, label);
		}

		private static LocationData? GatherLocationData()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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_00eb: 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)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: 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_001c: 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)
		{
			return BossLocationNames.Contains(locationName) || LocationPriorities.ContainsKey(locationName) || RegisteredLocationNames.Contains(locationName);
		}

		private static int GetMaxLocationsForIsland(Island island)
		{
			int num = 2 + (int)(island.ApproxArea / 2000000f);
			return Mathf.Clamp(num, 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)
		{
			int value;
			return LocationPriorities.TryGetValue(locationName, out value) ? value : 20;
		}

		private static void GenerateChainRoads(Vector3 startPos, float startRadius, List<(string name, Vector3 position, float radius)> locations)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_0021: 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_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: 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_0030: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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();
			RoadNetworkPersistence.Reset();
			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_002d: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: 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_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: 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);
			}
			return (list.Count >= 2) ? list : null;
		}

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

		public static void SaveGlobalRoadData()
		{
			if (!m_roadsGenerated)
			{
				Log.LogDebug((object)"[SAVE] No roads generated, skipping global save");
			}
			else
			{
				RoadNetworkPersistence.SaveGlobalRoadData(m_roadStartPoints);
			}
		}

		public static bool TryLoadGlobalRoadData()
		{
			return RoadNetworkPersistence.TryLoadGlobalRoadData(m_roadStartPoints);
		}
	}
	public static class RoadNetworkPersistence
	{
		public 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 readonly int GlobalRoadDataHash = StringExtensionMethods.GetStableHashCode("ProceduralRoads_GlobalData");

		private static ZDO? s_metadataZdo;

		private static readonly Vector3 FarPosition = new Vector3(50000f, 0f, 50000f);

		private static ManualLogSource Log => ProceduralRoadsPlugin.ProceduralRoadsLogger;

		public static void Reset()
		{
			s_metadataZdo = null;
		}

		public static void EnsureMetadataInstance()
		{
			//IL_0054: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			if (s_metadataZdo != null)
			{
				Log.LogDebug((object)"[META] Metadata ZDO already cached");
				return;
			}
			s_metadataZdo = FindMetadataZDO();
			if (s_metadataZdo != null)
			{
				MigrateZdoPosition(s_metadataZdo);
				Log.LogDebug((object)$"[META] Found existing metadata ZDO: {s_metadataZdo.m_uid}");
				return;
			}
			if (ZDOMan.instance == null)
			{
				Log.LogError((object)"[META] ZDOMan.instance is null!");
				return;
			}
			s_metadataZdo = ZDOMan.instance.CreateNewZDO(FarPosition, MetadataPrefabHash);
			s_metadataZdo.Persistent = true;
			s_metadataZdo.SetPrefab(MetadataPrefabHash);
			s_metadataZdo.SetOwner(ZDOMan.instance.m_sessionID);
			Log.LogDebug((object)$"[META] Created metadata ZDO directly: m_uid={s_metadataZdo.m_uid}, prefab={s_metadataZdo.GetPrefab()}, owner={s_metadataZdo.GetOwner()}");
		}

		public static void SaveGlobalRoadData(IReadOnlyList<(Vector2 position, string label)> roadStartPoints)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			Log.LogDebug((object)"[SAVE] SaveGlobalRoadData called");
			ZDO metadataZDO = GetMetadataZDO();
			if (metadataZDO == null)
			{
				Log.LogError((object)"[SAVE] No metadata ZDO available! EnsureMetadataInstance should have been called after road generation.");
				return;
			}
			if (!metadataZDO.IsOwner())
			{
				metadataZDO.SetOwner(ZDOMan.instance.m_sessionID);
				Log.LogDebug((object)"[SAVE] Claimed ownership of metadata ZDO");
			}
			Log.LogDebug((object)$"[SAVE] Using metadata ZDO: m_uid={metadataZDO.m_uid}, prefab={metadataZDO.GetPrefab()}, owner={metadataZDO.GetOwner()}");
			byte[] array = RoadSpatialGrid.SerializeAllRoadPoints();
			if (array != null && array.Length != 0)
			{
				metadataZDO.Set(GlobalRoadDataHash, array);
				Log.LogDebug((object)$"[SAVE] Saved global road data: {array.Length} bytes, {RoadSpatialGrid.GridCellsWithRoads} cells, {RoadSpatialGrid.TotalRoadPoints} points");
			}
			else
			{
				Log.LogWarning((object)"[SAVE] SerializeAllRoadPoints returned null or empty data!");
			}
			byte[] array2 = SerializeRoadStartPoints(roadStartPoints);
			if (array2 != null && array2.Length != 0)
			{
				metadataZDO.Set(RoadStartPointsHash, array2);
				Log.LogDebug((object)$"[SAVE] Saved {roadStartPoints.Count} road start points ({array2.Length} bytes)");
			}
		}

		public static bool TryLoadGlobalRoadData(List<(Vector2 position, string label)> roadStartPoints)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			Log.LogDebug((object)"[LOAD] TryLoadGlobalRoadData called");
			if (ZDOMan.instance == null)
			{
				Log.LogDebug((object)"[LOAD] ZDOMan.instance is null!");
				return false;
			}
			ZDO val = FindMetadataZDO();
			if (val == null)
			{
				Log.LogDebug((object)"[LOAD] No road metadata ZDO found");
				return false;
			}
			Log.LogDebug((object)$"[LOAD] Found metadata ZDO: m_uid={val.m_uid}, prefab={val.GetPrefab()}");
			byte[] byteArray = val.GetByteArray(GlobalRoadDataHash, (byte[])null);
			if (byteArray == null || byteArray.Length == 0)
			{
				Log.LogDebug((object)"[LOAD] Metadata ZDO found but no global road data");
				return false;
			}
			Log.LogDebug((object)$"[LOAD] Got {byteArray.Length} bytes of road data, deserializing...");
			if (RoadSpatialGrid.DeserializeAllRoadPoints(byteArray))
			{
				Log.LogDebug((object)$"[LOAD] Successfully loaded: {RoadSpatialGrid.GridCellsWithRoads} cells, {RoadSpatialGrid.TotalRoadPoints} points");
				TryLoadRoadMetadata(roadStartPoints);
				return true;
			}
			Log.LogWarning((object)"[LOAD] DeserializeAllRoadPoints returned false!");
			return false;
		}

		public static bool TryLoadRoadMetadata(List<(Vector2 position, string label)> roadStartPoints)
		{
			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, roadStartPoints))
			{
				Log.LogDebug((object)$"Loaded {roadStartPoints.Count} road start points from ZDO");
				return true;
			}
			return false;
		}

		private static void MigrateZdoPosition(ZDO zdo)
		{
			//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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_004e: 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_006a: 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)
			Vector3 position = zdo.GetPosition();
			if (position.x < 15000f && position.x > -15000f && position.z < 15000f && position.z > -15000f)
			{
				Log.LogDebug((object)$"[META] Migrating metadata ZDO from {position} to {FarPosition}");
				zdo.SetPosition(FarPosition);
			}
		}

		private static ZDO? GetMetadataZDO()
		{
			if (s_metadataZdo != null)
			{
				return s_metadataZdo;
			}
			s_metadataZdo = FindMetadataZDO();
			return s_metadataZdo;
		}

		private static ZDO? FindMetadataZDO()
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			if (ZDOMan.instance == null)
			{
				Log.LogDebug((object)"[FIND] ZDOMan.instance is null");
				return null;
			}
			List<ZDO> list = new List<ZDO>();
			int num = 0;
			while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative("ProceduralRoads_Metadata", list, ref num))
			{
			}
			Log.LogDebug((object)string.Format("[FIND] Search complete: found {0} ZDOs matching '{1}'", list.Count, "ProceduralRoads_Metadata"));
			if (list.Count > 0)
			{
				ZDO val = list[0];
				Log.LogDebug((object)$"[FIND] Found ZDO: m_uid={val.m_uid}, prefab={val.GetPrefab()}, persistent={val.Persistent}");
				return val;
			}
			Log.LogDebug((object)"[FIND] No matching ZDO found");
			return null;
		}

		private static byte[] SerializeRoadStartPoints(IReadOnlyList<(Vector2 position, string label)> roadStartPoints)
		{
			//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_003b: 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)
			using MemoryStream memoryStream = new MemoryStream();
			using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
			binaryWriter.Write(roadStartPoints.Count);
			foreach (var (val, text) in 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, List<(Vector2 position, string label)> roadStartPoints)
		{
			//IL_00cf: 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;
				}
				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);
					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 static int MaxIterations;

		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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0031: 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_003f: 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_004d: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_0077: 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_0085: 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_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_00b9: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			MaxIterations = 10000;
			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_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0024: 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_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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_00c5: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: 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_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: 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)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: 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_002d: 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)
				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 < MaxIterations)
			{
				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_0001: 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_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_002b: 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_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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)
			return new Vector2((float)grid.x * 8f, (float)grid.y * 8f);
		}

		private float Heuristic(Vector2i from, Vector2i to)
		{
			//IL_0001: 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_0016: 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)
			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_0007: 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_003e: 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)
			float height = m_worldGen.GetHeight(pos.x, pos.y);
			float num = height;
			float num2 = height;
			for (int i = 0; i < 8; i++)
			{
				float num3 = (float)i * (float)Math.PI * 2f / 8f;
				float height2 = m_worldGen.GetHeight(pos.x + Mathf.Cos(num3) * 16f, pos.y + Mathf.Sin(num3) * 16f);
				num = Mathf.Min(num, height2);
				num2 = Mathf.Max(num2, height2);
			}
			return num2 - num;
		}

		private float GetMoveCost(Vector2i from, Vector2i to, int directionIndex)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: 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_014a: 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 height2 = m_worldGen.GetHeight(val2.x, val2.y);
			float num2 = Mathf.Abs(height2 - 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 height3 = m_worldGen.GetHeight(val2.x, val2.y);
			if (height3 < 28f)
			{
				return WaterPenalty * 2f;
			}
			if (height3 < 30.5f)
			{
				return WaterPenalty;
			}
			if (num2 > SteepSlopeThreshold)
			{
				return SteepSlopePenalty;
			}
			if (GetTerrainVariance(val2) > TerrainVarianceThreshold)
			{
				return TerrainVariancePenalty;
			}
			Biome biome = m_worldGen.GetBiome(val2.x, val2.y, 0.02f, false);
			if ((int)biome == 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_0007: 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_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_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_0037: 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_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				p = position;
				w = width;
				w2 = width * width;
				h = height;
			}
		}

		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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_0006: 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_0036: 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_0085: 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_008d: 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_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: 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;
			int num = ((instance != null) ? instance.GetSeed() : 0);
			int num2 = num;
			num2 = num2 * 31 + TotalRoadPoints;
			num2 = num2 * 31 + GridCellsWithRoads;
			num2 = num2 * 31 + (int)(TotalRoadLength * 10f);
			RoadNetworkVersion = num2;
			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_0016: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_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_0039: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_0054: 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_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_0060: 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_0070: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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_0097: 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_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)
			//IL_00ac: 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)
			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_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_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_0046: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			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_003d: 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_0045: 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)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_0098: 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++)
					{
						RoadPoint roadPoint = array[i];
						if (Vector2.Distance(roadPoint.p, point) < num2)
						{
							num++;
							break;
						}
					}
				}
				finally
				{
					m_roadCacheLock.ExitReadLock();
				}
			}
			return num;
		}

		private static void BlendWithExistingRoads(List<Vector2> points, List<float> heights, float width)
		{
			//IL_0033: 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)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_00a1: 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_0001: 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_000d: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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_0041: 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_0052: 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_006d: 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_0003: 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_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_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)
			//IL_0030: 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)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor((float)grid.x * 64f, (float)grid.y * 64f);
			Vector2 val2 = p - val;
			float num = 32f;
			return Mathf.Abs(val2.x) < r + num && Mathf.Abs(val2.y) < r + num;
		}

		private static void MergePoints(Dictionary<Vector2i, List<RoadPoint>> tempPoints)
		{
			//IL_0027: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_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_0031: 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_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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_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)
			Vector2i roadGrid = GetRoadGrid(wx, wy);
			m_roadCacheLock.EnterReadLock();
			try
			{
				if (roadGrid == m_cachedRoadGrid)
				{
					if (m_cachedRoadPoints != null)
					{
						GetWeight(m_cachedRoadPoints, wx, wy, out weight, out width);
						return;
					}
					weight = 0f;
					width = 0f;
					return;
				}
			}
			finally
			{
				m_roadCacheLock.ExitReadLock();
			}
			if (m_roadPoints.TryGetValue(roadGrid, out RoadPoint[] value))
			{
				GetWeight(value, wx, wy, out weight, out width);
				m_roadCacheLock.EnterWriteLock();
				try
				{
					m_cachedRoadGrid = roadGrid;
					m_cachedRoadPoints = value;
					return;
				}
				finally
				{
					m_roadCacheLock.ExitWriteLock();
				}
			}
			m_roadCacheLock.EnterWriteLock();
			try
			{
				m_cachedRoadGrid = roadGrid;
				m_cachedRoadPoints = null;
			}
			finally
			{
				m_roadCacheLock.ExitWriteLock();
			}
			weight = 0f;
			width = 0f;
		}

		private static void GetWeight(RoadPoint[] points, float wx, float wy, out float weight, out float width)
		{
			//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_002f: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(wx, wy);
			float num = 0f;
			float num2 = 0f;
			for (int i = 0; i < points.Length; i++)
			{
				RoadPoint roadPoint = points[i];
				float num3 = Vector2.SqrMagnitude(roadPoint.p - val);
				float num4 = roadPoint.w * 0.5f;
				float num5 = num4 * num4;
				if (num3 < num5)
				{
					float num6 = Mathf.Sqrt(num3);
					float num7 = num6 / num4;
					float num8;
					if (num7 < 0.6f)
					{
						num8 = 1f;
					}
					else
					{
						float t = (num7 - 0.6f) / 0.39999998f;
						num8 = 1f - Smoothstep(t);
					}
					if (num8 > num)
					{
						num = num8;
						num2 = roadPoint.w;
					}
				}
			}
			weight = num;
			width = num2;
		}

		private static float Smoothstep(float t)
		{
			t = Mathf.Clamp01(t);
			return t * t * (3f - 2f * t);
		}

		public static List<RoadPoint> GetRoadPointsInZone(Vector2i zoneID)
		{
			//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_0028: 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_0033: 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_005d: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			List<RoadPoint> list = new List<RoadPoint>();
			if (!m_initialized)
			{
				return list;
			}
			Vector3 zonePos = ZoneSystem.GetZonePos(zoneID);
			Vector2i roadGrid = GetRoadGrid(zonePos.x, zonePos.z);
			m_roadCacheLock.EnterReadLock();
			try
			{
				Vector2i key = default(Vector2i);
				for (int i = -1; i <= 1; i++)
				{
					for (int j = -1; j <= 1; j++)
					{
						((Vector2i)(ref key))..ctor(roadGrid.x + j, roadGrid.y + i);
						if (!m_roadPoints.TryGetValue(key, out RoadPoint[] value))
						{
							continue;
						}
						RoadPoint[] array = value;
						for (int k = 0; k < array.Length; k++)
						{
							RoadPoint item = array[k];
							if (item.p.x >= zonePos.x - 32f - item.w && item.p.x <= zonePos.x + 32f + item.w && item.p.y >= zonePos.z - 32f - item.w && item.p.y <= zonePos.z + 32f + item.w)
							{
								list.Add(item);
							}
						}
					}
				}
			}
			finally
			{
				m_roadCacheLock.ExitReadLock();
			}
			return list;
		}

		public static int GetTotalPointCount()
		{
			int num = 0;
			m_roadCacheLock.EnterReadLock();
			try
			{
				foreach (KeyValuePair<Vector2i, RoadPoint[]> roadPoint in m_roadPoints)
				{
					num += roadPoint.Value.Length;
				}
			}
			finally
			{
				m_roadCacheLock.ExitReadLock();
			}
			return num;
		}

		public static List<RoadPoint> GetRoadPointsNearPosition(Vector3 worldPos, float radius)
		{
			//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_0030: 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_004d: 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_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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			List<RoadPoint> list = new List<RoadPoint>();
			if (!m_initialized)
			{
				return list;
			}
			Vector2 pos2D = new Vector2(worldPos.x, worldPos.z);
			float num = radius * radius;
			int num2 = Mathf.CeilToInt(radius / 64f) + 1;
			Vector2i roadGrid = GetRoadGrid(worldPos.x, worldPos.z);
			m_roadCacheLock.EnterReadLock();
			try
			{
				Vector2i key = default(Vector2i);
				for (int i = -num2; i <= num2; i++)
				{
					for (int j = -num2; j <= num2; j++)
					{
						((Vector2i)(ref key))..ctor(roadGrid.x + j, roadGrid.y + i);
						if (!m_roadPoints.TryGetValue(key, out RoadPoint[] value))
						{
							continue;
						}
						RoadPoint[] array = value;
						for (int k = 0; k < array.Length; k++)
						{
							RoadPoint item = array[k];
							Vector2 val = item.p - pos2D;
							if (((Vector2)(ref val)).sqrMagnitude <= num)
							{
								list.Add(item);
							}
						}
					}
				}
			}
			finally
			{
				m_roadCacheLock.ExitReadLock();
			}
			list.Sort(delegate(RoadPoint a, RoadPoint b)
			{
				//IL_0001: 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_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_001d: 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_002d: Unknown result type (might be due to invalid IL or missing references)
				Vector2 val2 = a.p - pos2D;
				float sqrMagnitude = ((Vector2)(ref val2)).sqrMagnitude;
				val2 = b.p - pos2D;
				return sqrMagnitude.CompareTo(((Vect