Decompiled source of Procedural Roads v1.4.1
ProceduralRoads.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using Splatform; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ProceduralRoads")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("warpalicious")] [assembly: AssemblyProduct("ProceduralRoads")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("E0E2F92E-557C-4A05-9D89-AA92A0BD75C4")] [assembly: AssemblyFileVersion("1.4.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.4.1.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: "); for (int j = DebugInfo.WindowHeights.Length - num5; j < DebugInfo.WindowHeights.Length; j++) { stringBuilder3.Append($"{DebugInfo.WindowHeights[j]:F1}m "); } stringBuilder.AppendLine(stringBuilder3.ToString()); } } stringBuilder.AppendLine(); if (WorldGenerator.instance != null) { float height = WorldGenerator.instance.GetHeight(RoadPointPosition.x, RoadPointPosition.y); float blendedHeight = BiomeBlendedHeight.GetBlendedHeight(RoadPointPosition.x, RoadPointPosition.y, WorldGenerator.instance); stringBuilder.AppendLine("Height Comparison:"); stringBuilder.AppendLine($" Raw WorldGen height: {height:F2}m"); stringBuilder.AppendLine($" Biome-blended height: {blendedHeight:F2}m"); stringBuilder.AppendLine($" Blend difference: {blendedHeight - height:F2}m"); stringBuilder.AppendLine($" Road target: {DebugInfo.SmoothedHeight:F2}m"); } string text2 = stringBuilder.ToString(); Log.LogDebug((object)text2); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, $"Road point {DebugInfo.PointIndex}: delta={num:F2}m (see console)", 0, (Sprite)null); } } } public static class Game_Patch { [HarmonyPatch(typeof(Game), "SpawnPlayer")] public static class Game_SpawnPlayer_Patch { [HarmonyPostfix] public static void Postfix(Vector3 spawnPoint) { //IL_0000: 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_0008: 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_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0010: 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) 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.1")] [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.1"; internal const string Author = "warpalicious"; private const string ModGUID = "warpalicious.ProceduralRoads"; private static string ConfigFileName = "warpalicious.ProceduralRoads.cfg"; private static string ConfigFileFullPath; internal static string ConnectionError; private readonly Harmony _harmony = new Harmony("warpalicious.ProceduralRoads"); public static readonly ManualLogSource ProceduralRoadsLogger; public Texture2D tex; public static ConfigEntry<float> RoadWidth; public static ConfigEntry<string> CustomLocations; public static ConfigEntry<int> IslandRoadPercentage; public void Awake() { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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>())); CustomLocations = ((BaseUnityPlugin)this).Config.Bind<string>("Locations", "CustomLocations", "", "Comma-separated list of location names to include in road generation. Use this for locations added by Expand World Data or other mods. Example: Runestone_Boars,Runestone_Greydwarfs,MerchantCamp"); ApplyConfiguration(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmony.PatchAll(executingAssembly); SetupWatcher(); ProceduralRoadsLogger.LogInfo((object)"ProceduralRoads v1.4.1 loaded - Procedural roads enabled"); if (saveOnConfigSet) { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; ((BaseUnityPlugin)this).Config.Save(); } } private void RegisterMetadataPrefab() { //IL_0005: 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_001c: Expected O, but got Unknown //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown GameObject val = new GameObject("ProceduralRoads_Metadata"); val.AddComponent<ZNetView>().m_persistent = true; CustomPrefab val2 = new CustomPrefab(val, false); PrefabManager.Instance.AddPrefab(val2); ProceduralRoadsLogger.LogDebug((object)"Registered metadata prefab: ProceduralRoads_Metadata"); } private static void ApplyConfiguration() { RoadNetworkGenerator.RoadWidth = RoadWidth.Value; RoadNetworkGenerator.IslandRoadPercentage = IslandRoadPercentage.Value; } public static HashSet<string> GetConfigLocationNames() { HashSet<string> hashSet = new HashSet<string>(); if (string.IsNullOrWhiteSpace(CustomLocations.Value)) { return hashSet; } string[] array = CustomLocations.Value.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (!string.IsNullOrEmpty(text)) { hashSet.Add(text); } } return hashSet; } private void OnDestroy() { ((BaseUnityPlugin)this).Config.Save(); } private void SetupWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName); fileSystemWatcher.Changed += ReadConfigValues; fileSystemWatcher.Created += ReadConfigValues; fileSystemWatcher.Renamed += ReadConfigValues; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; } private void ReadConfigValues(object sender, FileSystemEventArgs e) { if (!File.Exists(ConfigFileFullPath)) { return; } try { ProceduralRoadsLogger.LogDebug((object)"ReadConfigValues called"); ((BaseUnityPlugin)this).Config.Reload(); ApplyConfiguration(); } catch { ProceduralRoadsLogger.LogError((object)("There was an issue loading your " + ConfigFileName)); ProceduralRoadsLogger.LogError((object)"Please check your config entries for spelling and format!"); } } static ProceduralRoadsPlugin() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName; ConnectionError = ""; ProceduralRoadsLogger = Logger.CreateLogSource("ProceduralRoads"); RoadWidth = null; CustomLocations = null; IslandRoadPercentage = null; } } public static class KeyboardExtensions { public static bool IsKeyDown(this KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey)) { return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey); } return false; } public static bool IsKeyHeld(this KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey)) { return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey); } return false; } } public static class 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_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown List<ClearArea> list = new List<ClearArea>(); List<RoadSpatialGrid.RoadPoint> roadPointsInZone = RoadSpatialGrid.GetRoadPointsInZone(zoneID); if (roadPointsInZone.Count == 0) { return list; } HashSet<Vector2i> hashSet = new HashSet<Vector2i>(); Vector2i val = default(Vector2i); Vector3 val2 = default(Vector3); foreach (RoadSpatialGrid.RoadPoint item in roadPointsInZone) { ((Vector2i)(ref val))..ctor(Mathf.RoundToInt(item.p.x / 4f), Mathf.RoundToInt(item.p.y / 4f)); if (!hashSet.Contains(val)) { hashSet.Add(val); ((Vector3)(ref val2))..ctor((float)val.x * 4f, 0f, (float)val.y * 4f); float num = item.w * 0.6f; list.Add(new ClearArea(val2, num)); } } return list; } } 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 = 1000; 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_0019: 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 { get { if (!m_roadsGenerated) { return m_roadsLoadedFromZDO; } return true; } } public static void RegisterLocation(string locationName) { if (!string.IsNullOrWhiteSpace(locationName)) { string text = locationName.Trim(); if (RegisteredLocationNames.Add(text)) { Log.LogDebug((object)("Registered location for roads: " + text)); } } } public static void UnregisterLocation(string locationName) { if (!string.IsNullOrWhiteSpace(locationName)) { string text = locationName.Trim(); if (RegisteredLocationNames.Remove(text)) { Log.LogDebug((object)("Unregistered location from roads: " + text)); } } } public static IReadOnlyCollection<string> GetRegisteredLocations() { return RegisteredLocationNames; } public static IReadOnlyList<(Vector2 position, string label)> GetRoadStartPoints() { return m_roadStartPoints; } public static void Initialize() { Reset(); } public static void MarkLocationsReady() { m_locationsReady = true; Log.LogDebug((object)"Locations marked ready for road generation"); } public static void MarkRoadsLoadedFromZDO() { m_roadsLoadedFromZDO = true; Log.LogDebug((object)"Roads marked as loaded from ZDO persistence"); } public static void GenerateRoads(bool force = false) { //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_025f: 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..."); foreach (string configLocationName in ProceduralRoadsPlugin.GetConfigLocationNames()) { if (RegisteredLocationNames.Add(configLocationName)) { Log.LogDebug((object)("Added config location: " + configLocationName)); } } DateTime now = DateTime.Now; m_pathfinder = new RoadPathfinder(WorldGenerator.instance); m_roadsGeneratedCount = 0; LocationData? locationData = GatherLocationData(); if (!locationData.HasValue) { return; } List<Island> list = IslandDetector.DetectIslands(); List<Island> list2 = list.OrderByDescending((Island i) => i.ApproxArea).ToList(); int num = Mathf.Max(1, Mathf.RoundToInt((float)(list2.Count * IslandRoadPercentage) / 100f)); List<Island> list3 = list2.Take(num).ToList(); Log.LogDebug((object)$"Islands: {list.Count} total, {num} selected ({IslandRoadPercentage}%)"); foreach (Island item in list3) { List<(string, Vector3, float)> locationsOnIsland = GetLocationsOnIsland(item, locationData.Value.AllLocations); if (locationsOnIsland.Count != 0) { int maxLocationsForIsland = GetMaxLocationsForIsland(item); List<(string, Vector3, float)> list4 = SelectLocations(locationsOnIsland, maxLocationsForIsland); Log.LogDebug((object)$"Island {item.Id}: {locationsOnIsland.Count} candidates -> {list4.Count} selected (max {maxLocationsForIsland}, area {item.ApproxArea / 1000000f:F1}km²)"); if (item.ContainsPoint(locationData.Value.SpawnPoint)) { GenerateIslandRoads(item, list4, locationData.Value.SpawnPoint, locationData.Value.SpawnRadius); } else { GenerateIslandRoads(item, list4); } } } TimeSpan elapsed = DateTime.Now - now; LogGenerationStats(m_roadsGeneratedCount, elapsed); RoadSpatialGrid.FinalizeRoadNetwork(); m_roadsGenerated = true; m_pathfinder = null; RoadNetworkPersistence.EnsureMetadataInstance(); } public static bool GenerateRoad(Vector2 startCenter, float startRadius, Vector2 endCenter, float endRadius, float width, string? label = null) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) if (m_pathfinder == null) { Log.LogWarning((object)"GenerateRoad called without active pathfinder"); return false; } List<Vector2> list = m_pathfinder.FindPath(startCenter, endCenter); Canvas.ForceUpdateCanvases(); if (list == null || list.Count < 2) { if (label != null) { Log.LogWarning((object)("Could not find path: " + label)); } return false; } list = TrimPathToRadii(list, startCenter, startRadius, endCenter, endRadius); if (list == null || list.Count < 2) { if (label != null) { Log.LogWarning((object)("Path too short after trimming: " + label)); } return false; } RoadSpatialGrid.AddRoadPath(list, width, WorldGenerator.instance); m_roadsGeneratedCount++; if (list.Count > 0) { string item = label ?? $"Road {m_roadsGeneratedCount}"; m_roadStartPoints.Add((list[0], item)); } if (label != null) { Log.LogDebug((object)$"Generated road: {label} ({list.Count} waypoints)"); } return true; } public static bool GenerateRoad(Vector3 startPos, float startRadius, Vector3 endPos, float endRadius, float width, string? label = null) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) return RoadNetworkGenerator.GenerateRoad(new Vector2(startPos.x, startPos.z), startRadius, new Vector2(endPos.x, endPos.z), endRadius, width, label); } private static LocationData? GatherLocationData() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) Dictionary<Vector2i, LocationInstance>.ValueCollection locationList = ZoneSystem.instance.GetLocationList(); if (locationList == null || locationList.Count == 0) { Log.LogWarning((object)"No location instances found"); return null; } Vector3? val = null; float spawnRadius = 0f; List<(string, Vector3, float)> list = new List<(string, Vector3, float)>(); List<(string, Vector3, float)> list2 = new List<(string, Vector3, float)>(); foreach (LocationInstance item in locationList) { string name = item.m_location.m_prefab.Name; float exteriorRadius = item.m_location.m_exteriorRadius; list2.Add((name, item.m_position, exteriorRadius)); if (name == "StartTemple") { val = item.m_position; spawnRadius = exteriorRadius; } else if (BossLocationNames.Contains(name)) { list.Add((name, item.m_position, exteriorRadius)); } } if (!val.HasValue) { Log.LogWarning((object)"Could not find spawn point (StartTemple)"); val = Vector3.zero; } Log.LogDebug((object)$"Found spawn at {val.Value}, {list.Count} boss locations, {list2.Count} total locations"); LocationData value = default(LocationData); value.SpawnPoint = val.Value; value.SpawnRadius = spawnRadius; value.BossLocations = list; value.AllLocations = list2; return value; } private static List<(string name, Vector3 position, float radius)> GetLocationsOnIsland(Island island, List<(string name, Vector3 position, float radius)> allLocations) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) List<(string, Vector3, float)> list = new List<(string, Vector3, float)>(); foreach (var allLocation in allLocations) { if (island.ContainsPoint(allLocation.position) && IsRoadLocation(allLocation.name)) { list.Add(allLocation); } } return list; } private static bool IsRoadLocation(string locationName) { if (!BossLocationNames.Contains(locationName) && !LocationPriorities.ContainsKey(locationName)) { return RegisteredLocationNames.Contains(locationName); } return true; } private static int GetMaxLocationsForIsland(Island island) { return Mathf.Clamp(2 + (int)(island.ApproxArea / 2000000f), 2, 12); } private static List<(string name, Vector3 position, float radius)> SelectLocations(List<(string name, Vector3 position, float radius)> candidates, int maxCount) { if (candidates.Count <= maxCount) { return candidates; } return candidates.OrderByDescending<(string, Vector3, float), int>(((string name, Vector3 position, float radius) loc) => GetLocationPriority(loc.name)).Take(maxCount).ToList(); } private static int GetLocationPriority(string locationName) { if (!LocationPriorities.TryGetValue(locationName, out var value)) { return 20; } return value; } private static void GenerateChainRoads(Vector3 startPos, float startRadius, List<(string name, Vector3 position, float radius)> locations) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) if (locations.Count == 0) { return; } List<(string, Vector3, float)> list = new List<(string, Vector3, float)>(locations); Vector3 val = startPos; float startRadius2 = startRadius; string text = "Start"; while (list.Count > 0) { int index = 0; float num = float.MaxValue; for (int i = 0; i < list.Count; i++) { float num2 = Vector3.Distance(val, list[i].Item2); if (num2 < num) { num = num2; index = i; } } (string, Vector3, float) tuple = list[index]; list.RemoveAt(index); GenerateRoad(val, startRadius2, tuple.Item2, tuple.Item3, RoadWidth, text + " -> " + tuple.Item1); val = tuple.Item2; startRadius2 = tuple.Item3; (text, _, _) = tuple; } } private static void GenerateMSTRoads(Vector3 startPos, float startRadius, List<(string name, Vector3 position, float radius)> locations) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) if (locations.Count == 0) { return; } List<(string, Vector3, float)> list = new List<(string, Vector3, float)>(); list.Add(("Start", startPos, startRadius)); list.AddRange(locations); bool[] array = new bool[list.Count]; float[] array2 = new float[list.Count]; int[] array3 = new int[list.Count]; for (int i = 0; i < list.Count; i++) { array2[i] = float.MaxValue; array3[i] = -1; } array2[0] = 0f; for (int j = 0; j < list.Count; j++) { int num = -1; for (int k = 0; k < list.Count; k++) { if (!array[k] && (num == -1 || array2[k] < array2[num])) { num = k; } } if (num == -1 || array2[num] == float.MaxValue) { break; } array[num] = true; for (int l = 0; l < list.Count; l++) { if (!array[l]) { float num2 = Vector3.Distance(list[num].Item2, list[l].Item2); if (num2 < array2[l]) { array2[l] = num2; array3[l] = num; } } } } for (int m = 1; m < list.Count; m++) { if (array3[m] >= 0) { (string, Vector3, float) tuple = list[array3[m]]; (string, Vector3, float) tuple2 = list[m]; GenerateRoad(tuple.Item2, tuple.Item3, tuple2.Item2, tuple2.Item3, RoadWidth, tuple.Item1 + " -> " + tuple2.Item1); } } } private static void GenerateIslandRoads(Island island, List<(string name, Vector3 position, float radius)> islandLocations, Vector3? overrideStart = null, float overrideStartRadius = 0f) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) if (islandLocations.Count != 0) { Vector3 value = default(Vector3); float startRadius; if (overrideStart.HasValue) { value = overrideStart.Value; startRadius = overrideStartRadius; } else { Vector2 edgePoint = island.GetEdgePoint(); ((Vector3)(ref value))..ctor(edgePoint.x, 0f, edgePoint.y); startRadius = 0f; } bool flag = island.Id % 2 == 0; Log.LogDebug((object)string.Format("Island {0}: {1} locations, strategy={2}", island.Id, islandLocations.Count, flag ? "MST" : "Chain")); if (flag) { GenerateMSTRoads(value, startRadius, islandLocations); } else { GenerateChainRoads(value, startRadius, islandLocations); } } } public static void Reset() { m_roadsGenerated = false; m_locationsReady = false; m_roadsLoadedFromZDO = false; m_pathfinder = null; m_roadsGeneratedCount = 0; m_roadStartPoints.Clear(); 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) if (path == null || path.Count < 2) { return null; } int num = 0; float num2 = startRadius * startRadius; Vector2 val; for (int i = 0; i < path.Count; i++) { val = path[i] - startCenter; if (((Vector2)(ref val)).sqrMagnitude > num2) { num = i; break; } } int num3 = path.Count - 1; float num4 = endRadius * endRadius; for (int num5 = path.Count - 1; num5 >= 0; num5--) { val = path[num5] - endCenter; if (((Vector2)(ref val)).sqrMagnitude > num4) { num3 = num5; break; } } if (num3 <= num) { return null; } List<Vector2> list = new List<Vector2>(); if (num > 0 && num < path.Count) { Vector2 item = CalculateRadiusIntersection(path[num], startCenter, startRadius); list.Add(item); } for (int j = num; j <= num3; j++) { list.Add(path[j]); } if (num3 < path.Count - 1 && num3 >= 0) { Vector2 item2 = CalculateRadiusIntersection(path[num3], endCenter, endRadius); list.Add(item2); } if (list.Count < 2) { return null; } return list; } private static Vector2 CalculateRadiusIntersection(Vector2 outsidePoint, Vector2 center, float radius) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) Vector2 val = outsidePoint - center; Vector2 normalized = ((Vector2)(ref val)).normalized; return center + normalized * radius; } public static void 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: 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_005a: 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_004c: 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_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_0021: 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_0045: 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_0060: 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_0074: 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_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_0037: 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) 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_00af: 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 const int MaxIterations = 1000; public float SlopeMultiplier = 10f; public float RiverPenalty = 100000f; public float WaterPenalty = 100000f; public float SteepSlopePenalty = 2000f; public float SteepSlopeThreshold = 0.6f; public float TerrainVariancePenalty = 1000f; public float TerrainVarianceThreshold = 5f; public float BaseCost = 1f; private static readonly Vector2Int[] Directions; private static readonly float[] DirectionCosts; private WorldGenerator m_worldGen; private static ManualLogSource Log => ProceduralRoadsPlugin.ProceduralRoadsLogger; static RoadPathfinder() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) Directions = (Vector2Int[])(object)new Vector2Int[16] { new Vector2Int(1, 0), new Vector2Int(-1, 0), new Vector2Int(0, 1), new Vector2Int(0, -1), new Vector2Int(1, 1), new Vector2Int(-1, 1), new Vector2Int(1, -1), new Vector2Int(-1, -1), new Vector2Int(2, 1), new Vector2Int(2, -1), new Vector2Int(-2, 1), new Vector2Int(-2, -1), new Vector2Int(1, 2), new Vector2Int(-1, 2), new Vector2Int(1, -2), new Vector2Int(-1, -2) }; DirectionCosts = new float[Directions.Length]; for (int i = 0; i < Directions.Length; i++) { DirectionCosts[i] = Mathf.Sqrt((float)(((Vector2Int)(ref Directions[i])).x * ((Vector2Int)(ref Directions[i])).x + ((Vector2Int)(ref Directions[i])).y * ((Vector2Int)(ref Directions[i])).y)); } } public RoadPathfinder(WorldGenerator worldGen) { m_worldGen = worldGen; } public List<Vector2>? FindPath(Vector2 start, Vector2 end) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) Vector2i val = WorldToGrid(start); Vector2i val2 = WorldToGrid(end); if (val == val2) { return new List<Vector2> { start, end }; } SortedSet<(float, Vector2i)> sortedSet = new SortedSet<(float, Vector2i)>(Comparer<(float, Vector2i)>.Create(delegate((float priority, Vector2i pos) a, (float priority, Vector2i pos) b) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) int num4 = a.priority.CompareTo(b.priority); if (num4 != 0) { return num4; } num4 = a.pos.x.CompareTo(b.pos.x); return (num4 != 0) ? num4 : a.pos.y.CompareTo(b.pos.y); })); Dictionary<Vector2i, float> dictionary = new Dictionary<Vector2i, float>(); Dictionary<Vector2i, Vector2i> dictionary2 = new Dictionary<Vector2i, Vector2i>(); HashSet<Vector2i> hashSet = new HashSet<Vector2i>(); sortedSet.Add((Heuristic(val, val2), val)); dictionary[val] = 0f; int num = 0; Vector2i val3 = default(Vector2i); while (sortedSet.Count > 0 && num < 1000) { num++; (float, Vector2i) min = sortedSet.Min; sortedSet.Remove(min); Vector2i item = min.Item2; if (item == val2) { return ReconstructPath(dictionary2, item, start, end); } hashSet.Add(item); for (int i = 0; i < Directions.Length; i++) { ((Vector2i)(ref val3))..ctor(item.x + ((Vector2Int)(ref Directions[i])).x, item.y + ((Vector2Int)(ref Directions[i])).y); if (hashSet.Contains(val3)) { continue; } float moveCost = GetMoveCost(item, val3, i); if (!(moveCost >= RiverPenalty)) { float num2 = dictionary[item] + moveCost; if (!dictionary.TryGetValue(val3, out var value) || num2 < value) { dictionary2[val3] = item; dictionary[val3] = num2; float num3 = Heuristic(val3, val2); sortedSet.Remove((value + num3, val3)); sortedSet.Add((num2 + num3, val3)); } } } } string arg = ((sortedSet.Count == 0) ? "no reachable path" : "max iterations reached"); Log.LogWarning((object)$"Pathfinding failed: {arg} after {num} iterations"); return null; } private Vector2i WorldToGrid(Vector2 world) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) return new Vector2i(Mathf.RoundToInt(world.x / 8f), Mathf.RoundToInt(world.y / 8f)); } private Vector2 GridToWorld(Vector2i grid) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) return new Vector2((float)grid.x * 8f, (float)grid.y * 8f); } private float Heuristic(Vector2i from, Vector2i to) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) float num = (float)(to.x - from.x) * 8f; float num2 = (float)(to.y - from.y) * 8f; return Mathf.Sqrt(num * num + num2 * num2); } private float GetTerrainVariance(Vector2 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) float num; float num2 = (num = m_worldGen.GetHeight(pos.x, pos.y)); for (int i = 0; i < 8; i++) { float num3 = (float)i * (float)Math.PI * 2f / 8f; float height = m_worldGen.GetHeight(pos.x + Mathf.Cos(num3) * 16f, pos.y + Mathf.Sin(num3) * 16f); num = Mathf.Min(num, height); num2 = Mathf.Max(num2, height); } return num2 - num; } private float GetMoveCost(Vector2i from, Vector2i to, int directionIndex) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Invalid comparison between Unknown and I4 Vector2 val = GridToWorld(from); Vector2 val2 = GridToWorld(to); float num = DirectionCosts[directionIndex] * 8f; float height = m_worldGen.GetHeight(val.x, val.y); float num2 = Mathf.Abs(m_worldGen.GetHeight(val2.x, val2.y) - height) / num; float num3 = default(float); float num4 = default(float); m_worldGen.GetRiverWeight(val2.x, val2.y, ref num3, ref num4); if (num3 > 0.5f) { return RiverPenalty; } float height2 = m_worldGen.GetHeight(val2.x, val2.y); if (height2 < 28f) { return WaterPenalty * 2f; } if (height2 < 30.5f) { return WaterPenalty; } if (num2 > SteepSlopeThreshold) { return SteepSlopePenalty; } if (GetTerrainVariance(val2) > TerrainVarianceThreshold) { return TerrainVariancePenalty; } if ((int)m_worldGen.GetBiome(val2.x, val2.y, 0.02f, false) == 4 && num2 > 0.4f) { return WaterPenalty; } float num5 = ((num3 > 0f) ? (WaterPenalty * num3) : 0f); return BaseCost * num + num2 * num2 * SlopeMultiplier + num5; } private List<Vector2> ReconstructPath(Dictionary<Vector2i, Vector2i> cameFrom, Vector2i current, Vector2 start, Vector2 end) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) List<Vector2> list = new List<Vector2> { end }; while (cameFrom.ContainsKey(current)) { list.Add(GridToWorld(current)); current = cameFrom[current]; } list.Add(start); list.Reverse(); return list; } } public static class RoadSpatialGrid { public struct RoadPoint { public Vector2 p; public float w; public float w2; public float h; public RoadPoint(Vector2 position, float width, float height) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) p = position; w = width; w2 = width * width; h = height; } } public const float GridSize = 64f; public const float DefaultRoadWidth = 4f; private static Dictionary<Vector2i, RoadPoint[]> m_roadPoints = new Dictionary<Vector2i, RoadPoint[]>(); private static RoadPoint[]? m_cachedRoadPoints; private static Vector2i m_cachedRoadGrid = new Vector2i(-999999, -999999); private static ReaderWriterLockSlim m_roadCacheLock = new ReaderWriterLockSlim(); private static bool m_initialized = false; private static Dictionary<Vector2, RoadPointDebugInfo> m_debugInfo = new Dictionary<Vector2, RoadPointDebugInfo>(); public static readonly int RoadDataHash = StringExtensionMethods.GetStableHashCode("ProceduralRoads_RoadData"); public static int TotalRoadPoints { get; private set; } = 0; public static int GridCellsWithRoads { get; private set; } = 0; public static float TotalRoadLength { get; private set; } = 0f; public static int RoadNetworkVersion { get; private set; } = 0; private static ManualLogSource Log => ProceduralRoadsPlugin.ProceduralRoadsLogger; public static bool IsInitialized => m_initialized; public static void Clear() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) m_roadCacheLock.EnterWriteLock(); try { m_roadPoints.Clear(); m_cachedRoadPoints = null; m_cachedRoadGrid = new Vector2i(-999999, -999999); m_initialized = false; TotalRoadPoints = 0; GridCellsWithRoads = 0; TotalRoadLength = 0f; RoadNetworkVersion = 0; m_debugInfo.Clear(); } finally { m_roadCacheLock.ExitWriteLock(); } } public static bool TryGetDebugInfo(Vector2 position, out RoadPointDebugInfo debugInfo) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return m_debugInfo.TryGetValue(position, out debugInfo); } public static void AddRoadPath(List<Vector2> path, float width, WorldGenerator worldGen) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) if (path == null || path.Count < 2 || worldGen == null) { return; } float segmentLength = width / 4f; float num = 0f; for (int i = 0; i < path.Count - 1; i++) { num += Vector2.Distance(path[i], path[i + 1]); } List<Vector2> list = SplinePath(path, segmentLength); List<float> list2 = new List<float>(list.Count); foreach (Vector2 item in list) { list2.Add(BiomeBlendedHeight.GetBlendedHeight(item.x, item.y, worldGen)); } List<RoadPointDebugInfo> debugInfos; List<float> list3 = SmoothHeights(list2, 41, out debugInfos); int num2 = DetectOverlap(list, width); if ((float)num2 > (float)list.Count * 0.3f) { Log.LogDebug((object)$"Road path overlaps with existing roads ({num2}/{list.Count} points), blending heights"); BlendWithExistingRoads(list, list3, width); } Log.LogDebug((object)$"Road path: {path.Count} waypoints -> {list.Count} dense points"); Log.LogDebug((object)$" Path length: {num:F0}m, smoothing window: {41} points"); Log.LogDebug((object)$" Overlap: {num2}/{list.Count} points overlap existing roads"); Dictionary<Vector2i, List<RoadPoint>> dictionary = new Dictionary<Vector2i, List<RoadPoint>>(); for (int j = 0; j < list.Count; j++) { AddRoadPoint(dictionary, list[j], width, list3[j]); m_debugInfo[list[j]] = debugInfos[j]; } MergePoints(dictionary); TotalRoadPoints += list.Count; TotalRoadLength += num; m_initialized = true; } public static void FinalizeRoadNetwork() { WorldGenerator instance = WorldGenerator.instance; RoadNetworkVersion = ((((instance != null) ? instance.GetSeed() : 0) * 31 + TotalRoadPoints) * 31 + GridCellsWithRoads) * 31 + (int)(TotalRoadLength * 10f); Log.LogDebug((object)$"Road network finalized: version={RoadNetworkVersion}, points={TotalRoadPoints}, cells={GridCellsWithRoads}"); } private static Vector2 CatmullRom(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) float num = t * t; float num2 = num * t; return 0.5f * (2f * p1 + (-p0 + p2) * t + (2f * p0 - 5f * p1 + 4f * p2 - p3) * num + (-p0 + 3f * p1 - 3f * p2 + p3) * num2); } private static List<Vector2> SplinePath(List<Vector2> waypoints, float segmentLength) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (waypoints.Count < 2) { return new List<Vector2>(waypoints); } List<Vector2> list = new List<Vector2>(); for (int i = 0; i < waypoints.Count - 1; i++) { Vector2 p = waypoints[Mathf.Max(0, i - 1)]; Vector2 val = waypoints[i]; Vector2 val2 = waypoints[i + 1]; Vector2 p2 = waypoints[Mathf.Min(waypoints.Count - 1, i + 2)]; float num = Vector2.Distance(val, val2); int num2 = Mathf.Max(1, Mathf.CeilToInt(num / segmentLength)); for (int j = 0; j < num2; j++) { float t = (float)j / (float)num2; list.Add(CatmullRom(p, val, val2, p2, t)); } } list.Add(waypoints[waypoints.Count - 1]); return list; } private static List<float> SmoothHeights(List<float> heights, int windowSize, out List<RoadPointDebugInfo> debugInfos) { debugInfos = new List<RoadPointDebugInfo>(heights.Count); if (heights.Count < 2) { if (heights.Count == 1) { debugInfos.Add(new RoadPointDebugInfo { PointIndex = 0, TotalPoints = 1, OriginalHeight = heights[0], SmoothedHeight = heights[0], ActualWindowSize = 1 }); } return new List<float>(heights); } List<float> list = new List<float>(heights.Count); int num = windowSize / 2; for (int i = 0; i < heights.Count; i++) { float num2 = 0f; int num3 = 0; int num4 = Mathf.Max(0, i - num); int num5 = Mathf.Min(heights.Count - 1, i + num); List<float> list2 = new List<float>(); for (int j = num4; j <= num5; j++) { num2 += heights[j]; num3++; list2.Add(heights[j]); } float num6 = num2 / (float)num3; list.Add(num6); debugInfos.Add(new RoadPointDebugInfo { PointIndex = i, TotalPoints = heights.Count, OriginalHeight = heights[i], SmoothedHeight = num6, WindowStart = num4, WindowEnd = num5, ActualWindowSize = num3, WindowHeights = list2.ToArray() }); } return list; } private static int DetectOverlap(List<Vector2> points, float width) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (!m_initialized || m_roadPoints.Count == 0) { return 0; } int num = 0; float num2 = width * 0.6f; foreach (Vector2 point in points) { Vector2i roadGrid = GetRoadGrid(point.x, point.y); m_roadCacheLock.EnterReadLock(); try { if (!m_roadPoints.TryGetValue(roadGrid, out RoadPoint[] value)) { continue; } RoadPoint[] array = value; for (int i = 0; i < array.Length; i++) { if (Vector2.Distance(array[i].p, point) < num2) { num++; break; } } } finally { m_roadCacheLock.ExitReadLock(); } } return num; } private static void BlendWithExistingRoads(List<Vector2> points, List<float> heights, float width) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if (!m_initialized || m_roadPoints.Count == 0) { return; } float num = width * 0.8f; for (int i = 0; i < points.Count; i++) { Vector2i roadGrid = GetRoadGrid(points[i].x, points[i].y); m_roadCacheLock.EnterReadLock(); try { if (!m_roadPoints.TryGetValue(roadGrid, out RoadPoint[] value)) { continue; } float num2 = 1f; float num3 = heights[i]; RoadPoint[] array = value; for (int j = 0; j < array.Length; j++) { RoadPoint roadPoint = array[j]; float num4 = Vector2.Distance(roadPoint.p, points[i]); if (num4 < num) { float num5 = 1f - num4 / num; num3 += roadPoint.h * num5; num2 += num5; } } if (num2 > 1f) { heights[i] = num3 / num2; } } finally { m_roadCacheLock.ExitReadLock(); } } } private static void AddRoadPoint(Dictionary<Vector2i, List<RoadPoint>> roadPoints, Vector2 p, float width, float height) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) Vector2i roadGrid = GetRoadGrid(p.x, p.y); int num = Mathf.CeilToInt(width / 64f); Vector2i val = default(Vector2i); for (int i = roadGrid.y - num; i <= roadGrid.y + num; i++) { for (int j = roadGrid.x - num; j <= roadGrid.x + num; j++) { ((Vector2i)(ref val))..ctor(j, i); if (InsideRoadGrid(val, p, width)) { if (!roadPoints.TryGetValue(val, out List<RoadPoint> value)) { value = new List<RoadPoint>(); roadPoints.Add(val, value); } value.Add(new RoadPoint(p, width, height)); } } } } private static bool InsideRoadGrid(Vector2i grid, Vector2 p, float r) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor((float)grid.x * 64f, (float)grid.y * 64f); Vector2 val2 = p - val; float num = 32f; if (Mathf.Abs(val2.x) < r + num) { return Mathf.Abs(val2.y) < r + num; } return false; } private static void MergePoints(Dictionary<Vector2i, List<RoadPoint>> tempPoints) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) m_roadCacheLock.EnterWriteLock(); try { foreach (KeyValuePair<Vector2i, List<RoadPoint>> tempPoint in tempPoints) { if (m_roadPoints.TryGetValue(tempPoint.Key, out RoadPoint[] value)) { List<RoadPoint> list = new List<RoadPoint>(value); list.AddRange(tempPoint.Value); m_roadPoints[tempPoint.Key] = list.ToArray(); } else { m_roadPoints.Add(tempPoint.Key, tempPoint.Value.ToArray()); } } GridCellsWithRoads = m_roadPoints.Count; m_cachedRoadGrid = new Vector2i(-999999, -999999); m_cachedRoadPoints = null; } finally { m_roadCacheLock.ExitWriteLock(); } } public static Vector2i GetRoadGrid(float wx, float wy) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.FloorToInt((wx + 32f) / 64f); int num2 = Mathf.FloorToInt((wy + 32f) / 64f); return new Vector2i(num, num2); } public static void GetRoadWeight(float wx, float wy, out float weight, out float width) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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) / num4; float num7; if (num6 < 0.6f) { num7 = 1f; } else { float t = (num6 - 0.6f) / 0.39999998f; num7 = 1f - Smoothstep(t); } if (num7 > num) { num = num7; 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_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_004c: 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_0085: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) 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); } } } } return list; } finally { m_roadCacheLock.ExitReadLock(); } } public static int GetTotalPointCount() { int num = 0; m_roadCacheLock.EnterReadLock(); try { foreach (KeyValuePair<Vector2i, RoadPoint[]> roadPoint in m_roadPoints) { num += roadPoint.Value.Length; } return num; } finally { m_roadCacheLock.ExitReadLock(); } } public static List<RoadPoint> GetRoadPointsNearPosition(Vector3 worldPos, float radius) { //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) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_008b: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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(((Vector2)(ref val2)).sqrMagnitude); }); return list; } public static byte[]? SerializeZoneRoadPoints(Vector2i zoneID) { //IL_0000: 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_0051: Unknown result type (might be due to invalid IL or missing references) List<RoadPoint> roadPointsInZone = GetRoadPointsInZone(zoneID); if (roadPointsInZone.Count == 0) { return null; } using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(roadPointsInZone.Count); foreach (RoadPoint item in roadPointsInZone) { binaryWriter.Write(item.p.x); binaryWriter.Write(item.p.y); binaryWriter.Write(item.w); binaryWriter.Write(item.h); } return memoryStream.ToArray(); } public static void DeserializeZoneRoadPoints(Vector2i zoneID, byte[] data) { //IL_00d6: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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) if (data == null || data.Length == 0) { return; } try { using MemoryStream input = new MemoryStream(data); using BinaryReader binaryReader = new BinaryReader(input); int num = binaryReader.ReadInt32(); if (num <= 0 || num > 100000) { return; } Dictionary<Vector2i, List<RoadPoint>> dictionary = new Dictionary<Vector2i, List<RoadPoint>>(); for (int i = 0; i < num; i++) { float num2 = binaryReader.ReadSingle(); float num3 = binaryReader.ReadSingle(