using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("New Horizons Treelines")] [assembly: AssemblyDescription("New Horizons Treelines visual-only distant forest and terrain renderer for Valheim.")] [assembly: AssemblyCompany("Marc / Codex")] [assembly: AssemblyProduct("New Horizons Treelines")] [assembly: AssemblyFileVersion("4.6.31")] [assembly: AssemblyInformationalVersion("4.6.31")] [assembly: AssemblyVersion("4.6.31.0")] namespace DonegalHorizonLift; [BepInPlugin("marc.donegalhorizonlift", "New Horizons Treelines", "4.6.31")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class DonegalHorizonLiftPlugin : BaseUnityPlugin { private delegate float GetBaseHeightDelegate(WorldGenerator generator, float worldX, float worldZ, bool menuTerrain); private enum QualityPreset { VeryLow, Low, Balanced, Medium, High, Ultra, Horizon, Custom } private enum TreeCardDensityPreset { VeryLow, Low, Balanced, Medium, High, Ultra, Extreme, Custom } private enum NativeTreelineMode { AutoDetect, ManualCalibrated, DefaultFallback } private enum WorldDataMode { Auto, BetterContinentsCustomMap, ProceduralWorld } private enum HazeControlMode { Disabled, Auto, YieldToExternal, ForceHorizonLiftFog } private enum WaterSurfaceMode { Auto, Override, DisableLowlandForest } private enum ForestPlacementKind { TreeCard, BiomeCard, CanopyCard, ProxyMass, FillCard } private enum CardBaseHeightMode { LowestSupportedGround, LowerMiddleSupportedGround, MedianSupportedGround } private enum GroundRejectReason { None, Water, Unsupported, HeightMismatch, Other, BelowWater, VisibleLandRatio, CoastlineEdge, UncertainSupport, FinalFloating } private enum StrictFinalRejectReason { None, Floating, Burial, OpenWater, UnsupportedRoot } private enum RootAnchorMode { BottomCenter } private enum ClearSkyWeatherTier { Clear, PartlyClear, Bad, SpecialBiome } private enum TrueColourDiagnosticTarget { Off, NativeTerrainMaterial, NativeFogOutput, NewHorizonsFarTerrain, NewHorizonsTerrainTint, NewHorizonsHaze, ForestTerrainTint, NewHorizonsTreeCardMaterials } private enum ClearSkiesOperatingMode { Disabled, NaturalWeatherOnly, NaturalWeatherAndOccasionalEvent, PermanentCinematicOverride } private enum ForestRing { Handoff, Near, Mid, Far, Horizon } private enum ViewFacingForestOverloadState { Normal, Soft, Hard } private struct RingPlaneCounts { public int Tree; public int Canopy; public int PrimaryTree; public int OptionalTree; } private struct AtlasVisibleBounds { public float MinU; public float MaxU; public float MinV; public float MaxV; public float WidthFraction; public float HeightFraction; public Vector2 Root; public static AtlasVisibleBounds Full => new AtlasVisibleBounds { MinU = 0f, MaxU = 1f, MinV = 0f, MaxV = 1f, WidthFraction = 1f, HeightFraction = 1f, Root = new Vector2(0.5f, 0f) }; } private struct TreeRendererPropertyState { public Color Colour; } private sealed class ForestDeterminismRecord { public string Hash; public string GenerationSignature; public int CandidateTotal; public int CandidatesCompleted; public int[] StableCardRecords; } private readonly struct GroundCardSpatialRecord { public readonly float X; public readonly float Z; public readonly float BaseY; public readonly float Width; public readonly ForestPlacementKind Kind; public readonly Biome Biome; public readonly int GenerationEpoch; public GroundCardSpatialRecord(float x, float z, float baseY, float width, ForestPlacementKind kind, Biome biome, int generationEpoch) { //IL_0026: 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) X = x; Z = z; BaseY = baseY; Width = width; Kind = kind; Biome = biome; GenerationEpoch = generationEpoch; } } private readonly struct AcceptedCoverageCardRecord { public readonly float X; public readonly float Z; public readonly Biome Biome; public readonly int GenerationEpoch; public AcceptedCoverageCardRecord(float x, float z, Biome biome, int generationEpoch) { //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) X = x; Z = z; Biome = biome; GenerationEpoch = generationEpoch; } } private readonly struct CoverageSectorKey : IEquatable { public readonly int X; public readonly int Z; public readonly ForestRing Ring; public readonly int Epoch; public CoverageSectorKey(int x, int z, ForestRing ring, int epoch) { X = x; Z = z; Ring = ring; Epoch = epoch; } public bool Equals(CoverageSectorKey other) { if (X == other.X && Z == other.Z && Ring == other.Ring) { return Epoch == other.Epoch; } return false; } public override bool Equals(object obj) { if (obj is CoverageSectorKey) { return Equals((CoverageSectorKey)obj); } return false; } public override int GetHashCode() { return (int)(((uint)(((X * 397) ^ Z) * 397) ^ (uint)Ring) * 397) ^ Epoch; } } private sealed class CoverageSectorJob { public CoverageSectorKey Key; public int CellCursor; public int CellCount; public int GridSide; public int UnresolvedGapCells; public bool Dirty; public bool Completed; public float QueuedRealtime; public float LastProgressRealtime; } private enum RootAnchorRejectReason { None, Water, Unsupported, DryRatio, FloatHeight, WaterChannel, MissingValidation, MismatchedValidation, StaleValidation } private sealed class PresetRuntimeProfile { public QualityPreset Preset; public string Name; public float ExtensionDistance; public bool UseWorldMaximum; public int MaximumForestTiles; public int GlobalTreeCardPlaneBudget; public int GlobalCanopyPlaneBudget; public int PanicTileCeiling; public int TilesBuiltPerFrame; public int MaximumMeshUploadsPerFrame; } private sealed class TreeCardDensityProfile { public TreeCardDensityPreset Preset; public float ClusterCellSize; public float DensityThreshold; public float DensityMultiplier; public int CandidateTotal; public int CandidateStep; public int MaximumClusters; public int MaximumTreePlanes; public float MeadowsCoverage; public float BlackForestCoverage; public float NearRetention; public float MidRetention; public float FarRetention; public float HorizonRetention; public float HandoffGap; public float NearGap; public float MidGap; public float FarGap; public float HorizonGap; public float GlobalDistributedDensity; public float BlackForestDistributedDensity; public float MeadowsDistributedDensity; public float MountainDistributedDensity; public float PlainsDistributedDensity; public float HardRejectSlope; } private sealed class ForestBuildContinuation { public ForestAddJob Job; public ForestRing Ring; public ForestBuildResult Result; public IEnumerator Enumerator; public bool OptionalCoverageWasEnabled; public long GroundOwnerKey; public float StartedRealtime; public int CandidateIndex; public int CandidateTotal; public ViewFacingForestOverloadState GeometryOverloadState; public readonly List LeasedChunkBuffers = new List(32); } private sealed class ForestTileAssemblyResult { public ForestTile Tile; } private sealed class CoverageRepairJob { public float X; public float Z; public ForestRing Ring; public Biome Biome; public int AttemptsRemaining; public long QueueKey; public int StableRepairSeed; public int CoastalAttemptCursor; public bool CoastalSearchActive; public float QueuedRealtime; public bool DensityResolved; public float Density; } private sealed class CoverageRepairMeshBuffer { public readonly List Vertices = new List(256); public readonly List Uvs = new List(256); public readonly List Triangles = new List(384); public ForestTile Tile; public ForestChunk Chunk; public Mesh Mesh; } private enum ForestTileWorkState { None, Pending, Building, AwaitingUpload, Active, Cached, Retiring } private struct CalibrationSampleStats { public int Count; public float Min; public float Max; public float Median; public float P25; public float P75; public float MedianAbsoluteDeviation; public float DirectionalCoverageDegrees; } private interface IWorldDataProvider { string ProviderName { get; } bool IsReady { get; } float WorldRadius { get; } float ValidForestRange { get; } int StableSeed { get; } string WorldIdentity { get; } string HeightSource { get; } string BiomeSource { get; } string ForestSource { get; } string WaterSource { get; } string ExactSamplerStatus { get; } string TerrainOverlayStatus { get; } string CacheStatus { get; } bool UsesSharedTerrainTexture { get; } Texture2D SharedTerrainTexture { get; } bool TryInitialize(out string failureReason); bool TrySample(float worldX, float worldZ, out WorldSurfaceSample sample); Vector2 GetTerrainUv(float worldX, float worldZ); Color GetTerrainColor(float worldX, float worldZ, float distanceFromAnchor); void UpdateBackgroundWork(float budgetMs); void DeleteCache(); void Dispose(); } private struct WorldSurfaceSample { public bool Valid; public float GroundY; public Biome Biome; public float ForestDensity; public float SlopeDegrees; public bool IsWaterOrOcean; public string HeightSource; public string ForestSource; } private struct VisibleGroundSupportSample { public WorldSurfaceSample Surface; public float WaterHeight; public bool ExactSupport; public bool AboveVisibleWater; public bool WaterCovered; public bool OpenWater; public bool VisibleLand; } private struct PlacementValidationResult { public bool IsValid; public bool GroundLocked; public bool VisibleLandSupported; public float FinalBaseY; public ForestPlacementKind CardKind; public GroundRejectReason RejectReason; public Biome ValidatedBiome; public float ValidatedCenterX; public float ValidatedCenterZ; public float ValidatedWidth; public float ValidatedHeight; public float ValidatedDistance; public int ValidationEpoch; public long ValidationId; public bool RootAnchorValidated; public Vector3 RootAnchorWorldPosition; public float RootAnchorGroundY; public float RootAnchorWaterY; public float RootAnchorDrySampleRatio; public RootAnchorRejectReason RootAnchorRejectReason; public RootAnchorMode RootAnchorMode; public float RootAnchorAngle; public float RootPreLockBaseY; public float RootLockedBaseY; public int RootAnchorValidationEpoch; public long RootAnchorValidationId; public static PlacementValidationResult Valid(ForestPlacementKind kind, float finalBaseY) { return new PlacementValidationResult { IsValid = true, GroundLocked = true, VisibleLandSupported = true, FinalBaseY = finalBaseY, CardKind = kind, RejectReason = GroundRejectReason.None, RootAnchorValidated = false, RootAnchorRejectReason = RootAnchorRejectReason.MissingValidation }; } public static PlacementValidationResult Invalid(ForestPlacementKind kind, GroundRejectReason reason) { return new PlacementValidationResult { IsValid = false, GroundLocked = false, VisibleLandSupported = false, FinalBaseY = 0f, CardKind = kind, RejectReason = reason, RootAnchorValidated = false, RootAnchorRejectReason = RootAnchorRejectReason.MissingValidation }; } } private sealed class BetterContinentsCustomMapProvider : IWorldDataProvider { private readonly DonegalHorizonLiftPlugin _plugin; private WorldGenerator _worldGenerator; private GetBaseHeightDelegate _getBaseHeight; private Texture2D _heightMap; private Texture2D _colourMap; private Texture2D _forestMap; private Texture2D _overlayTexture; private Color32[] _colourPixels; private Color32[] _forestPixels; private BetterContinentsMapSettings _settings; private bool _ready; private float _waterLevel; private string _waterSource = "unresolved conservative"; public string ProviderName => "BetterContinentsCustomMap"; public bool IsReady => _ready; public float WorldRadius => _settings.TotalRadius; public float ValidForestRange => Mathf.Max(0f, _settings.WorldSize); public int StableSeed => StableStringSeed(WorldIdentity); public string WorldIdentity => "BC:" + _settings.TotalRadius.ToString("F0", CultureInfo.InvariantCulture) + ":" + _settings.ConfigHash; public string HeightSource => "private WorldGenerator.GetBaseHeight(float,float,bool) * 200"; public string BiomeSource => "WorldGenerator.GetBiome(Vector3)"; public string ForestSource => "forestmap.png"; public string WaterSource => _waterSource; public string ExactSamplerStatus { get { if (_getBaseHeight == null) { return "failed"; } return "linked"; } } public string TerrainOverlayStatus { get { Texture2D sharedTerrainTexture = SharedTerrainTexture; string text = ((_plugin._useUntintedProviderTerrainColourMap != null && _plugin._useUntintedProviderTerrainColourMap.Value) ? "original colour map" : "forested overlay"); if (!((Object)(object)sharedTerrainTexture != (Object)null)) { return "missing"; } return text + " / " + ((Texture)sharedTerrainTexture).width + "x" + ((Texture)sharedTerrainTexture).height; } } public string CacheStatus => "not used"; public bool UsesSharedTerrainTexture => true; public Texture2D SharedTerrainTexture { get { if (_plugin._useUntintedProviderTerrainColourMap != null && _plugin._useUntintedProviderTerrainColourMap.Value && (Object)(object)_colourMap != (Object)null) { return _colourMap; } return _overlayTexture; } } public BetterContinentsCustomMapProvider(DonegalHorizonLiftPlugin plugin) { _plugin = plugin; } public bool TryInitialize(out string failureReason) { failureReason = ""; if (!IsBetterContinentsPresent()) { failureReason = "Better Continents plugin GUID is not present."; return false; } if (!_plugin._useBetterContinentsExactSampler.Value) { failureReason = "Use Better Continents Exact Sampler is false. Final Donegal mode refuses direct/simple height fallback."; return false; } if (!TryLoadSettings(out failureReason)) { return false; } if (!TryLoadMaps(out failureReason)) { return false; } if (!TryBindExactSampler(out failureReason)) { return false; } ResolveWater(); _overlayTexture = CreateForestedOverlayTexture(); _ready = true; ((BaseUnityPlugin)_plugin).Logger.LogInfo((object)"Better Continents base-height sampler linked."); ((BaseUnityPlugin)_plugin).Logger.LogInfo((object)"Exact terrain-height mode active."); ((BaseUnityPlugin)_plugin).Logger.LogInfo((object)("Better Continents mapping: worldSize=" + _settings.WorldSize.ToString("F0") + " edgeSize=" + _settings.EdgeSize.ToString("F0") + " totalRadius=" + _settings.TotalRadius.ToString("F0") + " totalSpan=" + _settings.TotalSize.ToString("F0") + ". UV = Clamp(world/totalSpan + 0.5), PNG rows top-down.")); return true; } private static bool IsBetterContinentsPresent() { if (Chainloader.PluginInfos != null) { return Chainloader.PluginInfos.ContainsKey("BetterContinents"); } return false; } private bool TryLoadSettings(out string failure) { failure = ""; string text = ResolvePath(_plugin._betterContinentsConfigFile.Value, Paths.ConfigPath); if (!File.Exists(text)) { failure = "Missing BetterContinents.cfg at " + text; return false; } Dictionary values = ReadSimpleConfig(text); _settings = BetterContinentsMapSettings.CreateDefault(10500f); _settings.WorldSize = GetConfigFloat(values, "World Size", _settings.WorldSize); _settings.EdgeSize = GetConfigFloat(values, "Edge Size", _settings.EdgeSize); _settings.Recalculate(); _settings.ConfigHash = FileHashShort(text); return true; } private bool TryLoadMaps(out string failure) { failure = ""; string path = ResolvePath(_plugin._mapFolder.Value, Paths.PluginPath); string path2 = Path.Combine(path, _plugin._heightMapFile.Value); string path3 = Path.Combine(path, _plugin._colourMapFile.Value); string path4 = Path.Combine(path, _plugin._forestMapFile.Value); if (!File.Exists(path2) || !File.Exists(path3) || !File.Exists(path4)) { failure = "Required Donegal custom-map PNGs missing. height=" + File.Exists(path2) + " colour=" + File.Exists(path3) + " forest=" + File.Exists(path4); return false; } _heightMap = LoadPng(path2, (FilterMode)0); _colourMap = LoadPng(path3, (FilterMode)1); _forestMap = LoadPng(path4, (FilterMode)1); if (((Texture)_heightMap).width != ((Texture)_heightMap).height || ((Texture)_heightMap).width < 512) { failure = "heightmap.png is not a readable square map."; return false; } _colourPixels = _colourMap.GetPixels32(); _forestPixels = _forestMap.GetPixels32(); ((BaseUnityPlugin)_plugin).Logger.LogInfo((object)("Assets ready. Height " + ((Texture)_heightMap).width + "x" + ((Texture)_heightMap).height + "; colour " + ((Texture)_colourMap).width + "x" + ((Texture)_colourMap).height + "; forest " + ((Texture)_forestMap).width + "x" + ((Texture)_forestMap).height + ".")); return true; } private bool TryBindExactSampler(out string failure) { failure = ""; _worldGenerator = WorldGenerator.instance; if (_worldGenerator == null) { failure = "WorldGenerator.instance is not ready yet."; return false; } MethodInfo method = typeof(WorldGenerator).GetMethod("GetBaseHeight", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[3] { typeof(float), typeof(float), typeof(bool) }, null); if (method == null) { failure = "Could not find private WorldGenerator.GetBaseHeight(float,float,bool)."; return false; } _getBaseHeight = (GetBaseHeightDelegate)Delegate.CreateDelegate(typeof(GetBaseHeightDelegate), method); float num = SampleHeightOnly(0f, 0f); float num2 = SampleHeightOnly(0f, 4000f); float num3 = SampleHeightOnly(4000f, 0f); ((BaseUnityPlugin)_plugin).Logger.LogInfo((object)("Better Continents base-height sampler linked. Building far terrain ring. Samples (metres): center=" + num.ToString("F1") + ", north=" + num2.ToString("F1") + ", east=" + num3.ToString("F1") + ".")); return true; } public bool TrySample(float worldX, float worldZ, out WorldSurfaceSample sample) { //IL_008c: 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) //IL_00a7: 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_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_0063: Unknown result type (might be due to invalid IL or missing references) sample = default(WorldSurfaceSample); if (!_ready || _worldGenerator == null || _getBaseHeight == null || worldX * worldX + worldZ * worldZ > _settings.TotalRadius * _settings.TotalRadius) { return false; } float num = SampleHeightOnly(worldX, worldZ); Biome biome = (Biome)0; try { biome = _worldGenerator.GetBiome(new Vector3(worldX, 0f, worldZ)); } catch { } float num2 = SampleForestMap(worldX, worldZ); float slopeDegrees = CalculateSlope(worldX, worldZ, _plugin._slopeSampleRadius.Value); bool isWaterOrOcean = IsWater(biome, num, worldX, worldZ); sample.Valid = true; sample.GroundY = num; sample.Biome = biome; sample.ForestDensity = Mathf.Clamp01(num2); sample.SlopeDegrees = slopeDegrees; sample.IsWaterOrOcean = isWaterOrOcean; sample.HeightSource = HeightSource; sample.ForestSource = ForestSource; return true; } public Vector2 GetTerrainUv(float worldX, float worldZ) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) WorldToUvTopDown(worldX, worldZ, out var u, out var v); return new Vector2(u, 1f - v); } public Color GetTerrainColor(float worldX, float worldZ, float distanceFromAnchor) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_colourMap == (Object)null) { return Color.gray; } WorldToUvTopDown(worldX, worldZ, out var u, out var v); return SampleTextureColourTopDown(_colourPixels, ((Texture)_colourMap).width, ((Texture)_colourMap).height, u, v); } public void UpdateBackgroundWork(float budgetMs) { } public void DeleteCache() { } private float SampleHeightOnly(float worldX, float worldZ) { float num = _getBaseHeight(_worldGenerator, worldX, worldZ, menuTerrain: false); if (float.IsNaN(num) || float.IsInfinity(num)) { num = 0f; } return num * 200f; } private float CalculateSlope(float x, float z, float r) { float num = SampleHeightOnly(x + r, z); float num2 = SampleHeightOnly(x - r, z); float num3 = SampleHeightOnly(x, z + r); float num4 = SampleHeightOnly(x, z - r); float num5 = (num - num2) / (2f * r); float num6 = (num3 - num4) / (2f * r); return Mathf.Atan(Mathf.Sqrt(num5 * num5 + num6 * num6)) * 57.29578f; } private bool IsWater(Biome biome, float ground, float x, float z) { //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) if ((biome & 0x100) != 0) { return true; } if (_plugin._waterSurfaceMode.Value == WaterSurfaceMode.Override) { return ground <= _plugin._waterSurfaceHeightOverride.Value + _plugin._waterClearance.Value; } if (_plugin._waterSurfaceMode.Value == WaterSurfaceMode.Auto && (Object)(object)ZoneSystem.instance != (Object)null) { float waterLevel = ZoneSystem.instance.m_waterLevel; if (ground <= waterLevel + _plugin._waterClearance.Value) { return true; } if (ground <= waterLevel + _plugin._waterClearance.Value + 2f) { float value = _plugin._shoreSampleRadius.Value; if (!(SampleHeightOnly(x + value, z) <= waterLevel + _plugin._waterClearance.Value) && !(SampleHeightOnly(x - value, z) <= waterLevel + _plugin._waterClearance.Value) && !(SampleHeightOnly(x, z + value) <= waterLevel + _plugin._waterClearance.Value)) { return SampleHeightOnly(x, z - value) <= waterLevel + _plugin._waterClearance.Value; } return true; } } return false; } private void ResolveWater() { if (_plugin._waterSurfaceMode.Value == WaterSurfaceMode.Override) { _waterLevel = _plugin._waterSurfaceHeightOverride.Value; _waterSource = "override " + _waterLevel.ToString("F1", CultureInfo.InvariantCulture); } else if (_plugin._waterSurfaceMode.Value == WaterSurfaceMode.Auto && (Object)(object)ZoneSystem.instance != (Object)null) { _waterLevel = ZoneSystem.instance.m_waterLevel; _waterSource = "ZoneSystem.instance.m_waterLevel " + _waterLevel.ToString("F1", CultureInfo.InvariantCulture); } else { _waterSource = "unresolved conservative"; } } private Texture2D CreateForestedOverlayTexture() { //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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) Color32[] pixels = _colourMap.GetPixels32(); Color32[] array = (Color32[])(object)new Color32[pixels.Length]; Color val = ParseColor(_plugin._forestTerrainTintColour.Value, new Color(0.14f, 0.23f, 0.17f, 1f)); int width = ((Texture)_colourMap).width; int height = ((Texture)_colourMap).height; for (int i = 0; i < height; i++) { int num = height - 1 - i; float vTopDown = ((height > 1) ? ((float)num / (float)(height - 1)) : 0f); for (int j = 0; j < width; j++) { int num2 = i * width + j; float u = ((width > 1) ? ((float)j / (float)(width - 1)) : 0f); float num3 = Mathf.Clamp01(SamplePixels(_forestPixels, ((Texture)_forestMap).width, ((Texture)_forestMap).height, u, vTopDown) * _plugin.ForestDensityMultiplier()); Color val2 = Color32.op_Implicit(pixels[num2]); float num4 = Mathf.Clamp01((num3 - _plugin.ForestDensityThreshold()) / Mathf.Max(0.01f, 1f - _plugin.ForestDensityThreshold())); Color val3 = Color.Lerp(val2, val, num4 * _plugin.ForestTerrainTintStrength()); array[num2] = Color32.op_Implicit(val3); } } Texture2D val4 = new Texture2D(width, height, (TextureFormat)3, true, false); ((Object)val4).name = "DonegalForestedHorizonTexture_Runtime"; ((Texture)val4).wrapMode = (TextureWrapMode)1; ((Texture)val4).filterMode = (FilterMode)1; val4.SetPixels32(array); val4.Apply(true, false); return val4; } private float SampleForestMap(float worldX, float worldZ) { WorldToUvTopDown(worldX, worldZ, out var u, out var v); return SamplePixels(_forestPixels, ((Texture)_forestMap).width, ((Texture)_forestMap).height, u, v); } private void WorldToUvTopDown(float worldX, float worldZ, out float u, out float v) { float num = Mathf.Max(1f, _settings.TotalSize); u = Mathf.Clamp01(worldX / num + 0.5f); v = Mathf.Clamp01(worldZ / num + 0.5f); } public void Dispose() { if ((Object)(object)_heightMap != (Object)null) { Object.Destroy((Object)(object)_heightMap); } if ((Object)(object)_colourMap != (Object)null) { Object.Destroy((Object)(object)_colourMap); } if ((Object)(object)_forestMap != (Object)null) { Object.Destroy((Object)(object)_forestMap); } if ((Object)(object)_overlayTexture != (Object)null) { Object.Destroy((Object)(object)_overlayTexture); } _heightMap = null; _colourMap = null; _forestMap = null; _overlayTexture = null; _colourPixels = null; _forestPixels = null; _ready = false; } } private sealed class ProceduralWorldProvider : IWorldDataProvider { private readonly DonegalHorizonLiftPlugin _plugin; private WorldGenerator _worldGenerator; private GetBaseHeightDelegate _getBaseHeight; private bool _ready; private int _stableSeed; private string _worldIdentity = "procedural:pending"; private string _worldName = "unknown"; private string _waterSource = "unresolved conservative"; private float _waterLevel; public string ProviderName => "ProceduralWorld"; public bool IsReady => _ready; public float WorldRadius => _plugin._proceduralWorldRadius.Value; public float ValidForestRange => Mathf.Max(0f, WorldRadius - 500f); public int StableSeed => _stableSeed; public string WorldIdentity => _worldIdentity; public string HeightSource => "private WorldGenerator.GetBaseHeight(float,float,bool) * 200 (native procedural)"; public string BiomeSource => "WorldGenerator.GetBiome(Vector3)"; public string ForestSource => "deterministic biome-aware procedural density"; public string WaterSource => _waterSource; public string ExactSamplerStatus { get { if (_getBaseHeight == null) { return "failed"; } return "linked native procedural"; } } public string TerrainOverlayStatus => "per-tile procedural biome colour"; public string CacheStatus => "not used"; public bool UsesSharedTerrainTexture => false; public Texture2D SharedTerrainTexture => null; public ProceduralWorldProvider(DonegalHorizonLiftPlugin plugin) { _plugin = plugin; } public bool TryInitialize(out string failureReason) { failureReason = ""; if (!_plugin.IsGameplayWorldReady(out var reason)) { failureReason = reason; return false; } _worldGenerator = WorldGenerator.instance; if (_worldGenerator == null) { failureReason = "WorldGenerator.instance is not ready yet."; return false; } MethodInfo method = typeof(WorldGenerator).GetMethod("GetBaseHeight", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3] { typeof(float), typeof(float), typeof(bool) }, null); if (method == null || method.ReturnType != typeof(float)) { failureReason = "Could not find WorldGenerator.GetBaseHeight(float,float,bool) required for safe native procedural far terrain."; return false; } try { _getBaseHeight = (GetBaseHeightDelegate)Delegate.CreateDelegate(typeof(GetBaseHeightDelegate), method); } catch (Exception ex) { failureReason = "Could not bind WorldGenerator.GetBaseHeight(float,float,bool): " + ex.Message; return false; } ResolveWorldIdentity(); ResolveWater(); _ready = true; float num = SampleHeightOnly(0f, 0f); float num2 = SampleHeightOnly(0f, 4000f); float num3 = SampleHeightOnly(4000f, 0f); ((BaseUnityPlugin)_plugin).Logger.LogInfo((object)("ProceduralWorld sampler linked. World '" + _worldName + "', seed " + _stableSeed.ToString(CultureInfo.InvariantCulture) + ", radius " + WorldRadius.ToString("F0", CultureInfo.InvariantCulture) + "m. Samples (metres): center=" + num.ToString("F1", CultureInfo.InvariantCulture) + ", north=" + num2.ToString("F1", CultureInfo.InvariantCulture) + ", east=" + num3.ToString("F1", CultureInfo.InvariantCulture) + ".")); return true; } public bool TrySample(float worldX, float worldZ, out WorldSurfaceSample sample) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) sample = default(WorldSurfaceSample); if (!_ready || _worldGenerator == null || _getBaseHeight == null || worldX * worldX + worldZ * worldZ > WorldRadius * WorldRadius) { return false; } float num = SampleHeightOnly(worldX, worldZ); Biome biome = (Biome)0; try { biome = _worldGenerator.GetBiome(new Vector3(worldX, 0f, worldZ)); } catch { } float num2 = CalculateSlope(worldX, worldZ, _plugin._slopeSampleRadius.Value); bool flag = IsWater(biome, num, worldX, worldZ); sample.Valid = true; sample.GroundY = num; sample.Biome = biome; sample.ForestDensity = SampleForestDensity(worldX, worldZ, biome, num2, flag); sample.SlopeDegrees = num2; sample.IsWaterOrOcean = flag; sample.HeightSource = HeightSource; sample.ForestSource = ForestSource; return true; } public Vector2 GetTerrainUv(float worldX, float worldZ) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(1f, WorldRadius * 2f); return new Vector2(Mathf.Clamp01(worldX / num + 0.5f), Mathf.Clamp01(worldZ / num + 0.5f)); } public Color GetTerrainColor(float worldX, float worldZ, float distanceFromAnchor) { //IL_0001: 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_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_0040: 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) Biome biome = (Biome)0; try { biome = _worldGenerator.GetBiome(new Vector3(worldX, 0f, worldZ)); } catch { } float ground = SampleHeightOnly(worldX, worldZ); float noise = ProceduralNoise(worldX, worldZ, 650f, 0.62f, 0.38f); return BiomeTerrainColour(biome, ground, noise); } public void UpdateBackgroundWork(float budgetMs) { } public void DeleteCache() { } private float SampleHeightOnly(float worldX, float worldZ) { float num = _getBaseHeight(_worldGenerator, worldX, worldZ, menuTerrain: false); if (float.IsNaN(num) || float.IsInfinity(num)) { num = 0f; } return num * 200f; } private float CalculateSlope(float x, float z, float radius) { float num = Mathf.Max(0.5f, radius); float num2 = SampleHeightOnly(x + num, z); float num3 = SampleHeightOnly(x - num, z); float num4 = SampleHeightOnly(x, z + num); float num5 = SampleHeightOnly(x, z - num); float num6 = (num2 - num3) / (2f * num); float num7 = (num4 - num5) / (2f * num); return Mathf.Atan(Mathf.Sqrt(num6 * num6 + num7 * num7)) * 57.29578f; } private float SampleForestDensity(float worldX, float worldZ, Biome biome, float slope, bool water) { //IL_0004: 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_000d: 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_001b: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_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_006c: 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) if (water || (biome & 0x100) != 0 || (biome & 0x20) != 0) { return 0f; } float num = (((biome & 8) != 0) ? 0.86f : (((biome & 1) != 0) ? 0.52f : (((biome & 2) != 0) ? 0.68f : (((biome & 0x200) != 0) ? 0.62f : (((biome & 0x40) != 0) ? 0.42f : (((biome & 4) != 0) ? 0.24f : (((biome & 0x10) == 0) ? 0.28f : 0.2f))))))); float num2 = ProceduralNoise(worldX, worldZ, 1000f, 0.68f, 0.32f); float num3 = ProceduralNoise(worldX + 937.4f, worldZ - 571.9f, 280f, 0.45f, 0.55f); float num4 = num * Mathf.Lerp(0.38f, 1.18f, num2) * Mathf.Lerp(0.75f, 1.15f, num3); float num5 = 1f - Mathf.Clamp01(Mathf.InverseLerp(_plugin._slopeRejectionThreshold.Value * 0.7f, _plugin._hardSlopeRejectionThreshold.Value, slope)); return Mathf.Clamp01(num4 * num5); } private float ProceduralNoise(float worldX, float worldZ, float scale, float macroWeight, float detailWeight) { float num = (float)(_stableSeed & 0x7FFF) * 0.01337f; float num2 = (float)((_stableSeed >> 8) & 0x7FFF) * 0.01771f; float num3 = Mathf.PerlinNoise((worldX + num) / Mathf.Max(1f, scale), (worldZ + num2) / Mathf.Max(1f, scale)); float num4 = Mathf.PerlinNoise((worldX - num2 * 3.1f) / Mathf.Max(1f, scale * 0.31f), (worldZ + num * 2.3f) / Mathf.Max(1f, scale * 0.31f)); return Mathf.Clamp01(num3 * macroWeight + num4 * detailWeight); } private static Color BiomeTerrainColour(Biome biome, float ground, float noise) { //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_0029: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) Color val = default(Color); if ((biome & 0x100) != 0) { ((Color)(ref val))..ctor(0.08f, 0.17f, 0.23f, 1f); } else if ((biome & 0x20) != 0) { ((Color)(ref val))..ctor(0.24f, 0.13f, 0.1f, 1f); } else if ((biome & 0x200) != 0) { ((Color)(ref val))..ctor(0.22f, 0.26f, 0.21f, 1f); } else if ((biome & 2) != 0) { ((Color)(ref val))..ctor(0.18f, 0.25f, 0.16f, 1f); } else if ((biome & 8) != 0) { ((Color)(ref val))..ctor(0.17f, 0.27f, 0.16f, 1f); } else if ((biome & 4) != 0) { ((Color)(ref val))..ctor(0.46f, 0.47f, 0.45f, 1f); } else if ((biome & 0x40) != 0) { ((Color)(ref val))..ctor(0.56f, 0.61f, 0.62f, 1f); } else if ((biome & 0x10) != 0) { ((Color)(ref val))..ctor(0.44f, 0.42f, 0.2f, 1f); } else { ((Color)(ref val))..ctor(0.34f, 0.42f, 0.22f, 1f); } if ((biome & 4) != 0 && ground > 70f) { float num = Mathf.Clamp01(Mathf.InverseLerp(70f, 130f, ground)); val = Color.Lerp(val, new Color(0.78f, 0.8f, 0.79f, 1f), num * 0.7f); } float num2 = Mathf.Lerp(0.86f, 1.1f, noise); return new Color(Mathf.Clamp01(val.r * num2), Mathf.Clamp01(val.g * num2), Mathf.Clamp01(val.b * num2), 1f); } private bool IsWater(Biome biome, float ground, float x, float z) { //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) if ((biome & 0x100) != 0) { return true; } if (_plugin._waterSurfaceMode.Value == WaterSurfaceMode.Override) { return ground <= _plugin._waterSurfaceHeightOverride.Value + _plugin._waterClearance.Value; } if (_plugin._waterSurfaceMode.Value == WaterSurfaceMode.Auto && (Object)(object)ZoneSystem.instance != (Object)null) { float waterLevel = ZoneSystem.instance.m_waterLevel; if (ground <= waterLevel + _plugin._waterClearance.Value) { return true; } if (ground <= waterLevel + _plugin._waterClearance.Value + 2f) { float value = _plugin._shoreSampleRadius.Value; if (!(SampleHeightOnly(x + value, z) <= waterLevel + _plugin._waterClearance.Value) && !(SampleHeightOnly(x - value, z) <= waterLevel + _plugin._waterClearance.Value) && !(SampleHeightOnly(x, z + value) <= waterLevel + _plugin._waterClearance.Value)) { return SampleHeightOnly(x, z - value) <= waterLevel + _plugin._waterClearance.Value; } return true; } } return false; } private void ResolveWater() { if (_plugin._waterSurfaceMode.Value == WaterSurfaceMode.Override) { _waterLevel = _plugin._waterSurfaceHeightOverride.Value; _waterSource = "override " + _waterLevel.ToString("F1", CultureInfo.InvariantCulture); } else if (_plugin._waterSurfaceMode.Value == WaterSurfaceMode.Auto && (Object)(object)ZoneSystem.instance != (Object)null) { _waterLevel = ZoneSystem.instance.m_waterLevel; _waterSource = "ZoneSystem.instance.m_waterLevel " + _waterLevel.ToString("F1", CultureInfo.InvariantCulture); } else { _waterSource = "unresolved conservative"; } } private static object ReadStaticMember(Type type, params string[] names) { if (type == null) { return null; } for (int i = 0; i < names.Length; i++) { FieldInfo field = type.GetField(names[i], BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field.GetValue(null); } PropertyInfo property = type.GetProperty(names[i], BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.GetIndexParameters().Length == 0) { return property.GetValue(null, null); } } return null; } private void ResolveWorldIdentity() { _stableSeed = 91009; _worldName = "unknown"; try { Type type = typeof(WorldGenerator).Assembly.GetType("ZNet"); if (type != null) { object obj = ReadStaticMember(type, "instance", "Instance"); MethodInfo methodInfo = ((obj != null) ? type.GetMethod("GetWorld", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null) : null); object obj2 = ((methodInfo != null) ? methodInfo.Invoke(obj, null) : null); if (obj2 != null) { if (TryReadIntMember(obj2, out var value, "m_seed", "Seed", "seed")) { _stableSeed = value; } if (TryReadStringMember(obj2, out var value2, "m_name", "Name", "name") && !string.IsNullOrEmpty(value2)) { _worldName = value2; } } } if (_stableSeed == 91009 && TryReadIntMember(_worldGenerator, out var value3, "m_seed", "m_worldSeed", "Seed")) { _stableSeed = value3; } } catch (Exception ex) { ((BaseUnityPlugin)_plugin).Logger.LogWarning((object)("ProceduralWorld could not read active world identity; using stable fallback seed. " + ex.Message)); } _worldIdentity = "PROCEDURAL:" + _worldName + ":" + _stableSeed.ToString(CultureInfo.InvariantCulture) + ":" + Mathf.RoundToInt(WorldRadius).ToString(CultureInfo.InvariantCulture); } private static bool TryReadIntMember(object instance, out int value, params string[] names) { value = 0; if (instance == null) { return false; } Type type = instance.GetType(); for (int i = 0; i < names.Length; i++) { FieldInfo field = type.GetField(names[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(int)) { value = (int)field.GetValue(instance); return true; } PropertyInfo property = type.GetProperty(names[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.PropertyType == typeof(int) && property.GetIndexParameters().Length == 0) { value = (int)property.GetValue(instance, null); return true; } } return false; } private static bool TryReadStringMember(object instance, out string value, params string[] names) { value = ""; if (instance == null) { return false; } Type type = instance.GetType(); for (int i = 0; i < names.Length; i++) { FieldInfo field = type.GetField(names[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType == typeof(string)) { value = field.GetValue(instance) as string; return true; } PropertyInfo property = type.GetProperty(names[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.PropertyType == typeof(string) && property.GetIndexParameters().Length == 0) { value = property.GetValue(instance, null) as string; return true; } } return false; } public void Dispose() { _ready = false; _worldGenerator = null; _getBaseHeight = null; } } private sealed class TerrainTile { public readonly GameObject Root; public readonly MeshFilter Filter; public readonly MeshRenderer Renderer; public readonly Vector3 Center; public readonly float Size; public Mesh Mesh; public Material Material; public Texture2D Texture; public float[] HeightGrid; public int GridResolution; public TerrainTile(int x, int z, float size, Transform parent) { //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) Size = size; Center = new Vector3(((float)x + 0.5f) * size, 0f, ((float)z + 0.5f) * size); Root = CreateMeshObject("DonegalHorizonTerrainTile_" + x + "_" + z, parent, out Filter, out Renderer); } public void Destroy() { if ((Object)(object)Mesh != (Object)null) { Object.Destroy((Object)(object)Mesh); } if ((Object)(object)Material != (Object)null) { Object.Destroy((Object)(object)Material); } if ((Object)(object)Texture != (Object)null) { Object.Destroy((Object)(object)Texture); } if ((Object)(object)Root != (Object)null) { Object.Destroy((Object)(object)Root); } } } private sealed class ForestChunkBuffers { public int ChunkX; public int ChunkZ; public float ChunkSize; public int Shard; public bool Pooled; public readonly List MassVertices = new List(256); public readonly List MassTriangles = new List(384); public readonly List TreeVertices = new List(512); public readonly List TreeUvs = new List(512); public readonly List TreeTriangles = new List(768); public readonly List CanopyVertices = new List(256); public readonly List CanopyUvs = new List(256); public readonly List CanopyTriangles = new List(384); public readonly List MountainVertices = new List(256); public readonly List MountainUvs = new List(256); public readonly List MountainTriangles = new List(384); public readonly List SwampVertices = new List(256); public readonly List SwampUvs = new List(256); public readonly List SwampTriangles = new List(384); public int TreeBucketTreePlanes; public int CanopyBucketCanopyPlanes; public int MountainTreePlanes; public int MountainCanopyPlanes; public int SwampTreePlanes; public int SwampCanopyPlanes; public int DetailedLogicalCards; public int DetailedCrossedLogicalCards; public int DetailedSinglePlaneLogicalCards; public int DetailedTriangleCount => (TreeTriangles.Count + CanopyTriangles.Count + MountainTriangles.Count + SwampTriangles.Count) / 3; public int DetailedVertexCount => TreeVertices.Count + CanopyVertices.Count + MountainVertices.Count + SwampVertices.Count; public ForestChunkBuffers(int chunkX, int chunkZ, float chunkSize, int shard) { Prepare(chunkX, chunkZ, chunkSize, shard); } public void Prepare(int chunkX, int chunkZ, float chunkSize, int shard) { ChunkX = chunkX; ChunkZ = chunkZ; ChunkSize = chunkSize; Shard = shard; Pooled = false; TreeBucketTreePlanes = 0; CanopyBucketCanopyPlanes = 0; MountainTreePlanes = 0; MountainCanopyPlanes = 0; SwampTreePlanes = 0; SwampCanopyPlanes = 0; DetailedLogicalCards = 0; DetailedCrossedLogicalCards = 0; DetailedSinglePlaneLogicalCards = 0; } public void ClearForPool() { MassVertices.Clear(); MassTriangles.Clear(); TreeVertices.Clear(); TreeUvs.Clear(); TreeTriangles.Clear(); CanopyVertices.Clear(); CanopyUvs.Clear(); CanopyTriangles.Clear(); MountainVertices.Clear(); MountainUvs.Clear(); MountainTriangles.Clear(); SwampVertices.Clear(); SwampUvs.Clear(); SwampTriangles.Clear(); Pooled = true; } public void RecordLogicalTreeCard(bool singlePlane) { DetailedLogicalCards++; if (singlePlane) { DetailedSinglePlaneLogicalCards++; } else { DetailedCrossedLogicalCards++; } } public void RecordAtlasPlanes(List targetVertices, int count, bool canopy) { if (count <= 0) { return; } if (targetVertices == TreeVertices) { TreeBucketTreePlanes += count; } else if (targetVertices == CanopyVertices) { CanopyBucketCanopyPlanes += count; } else if (targetVertices == MountainVertices) { if (canopy) { MountainCanopyPlanes += count; } else { MountainTreePlanes += count; } } else if (targetVertices == SwampVertices) { if (canopy) { SwampCanopyPlanes += count; } else { SwampTreePlanes += count; } } } } private sealed class ForestChunkMeshSet { public int ChunkX; public int ChunkZ; public float ChunkSize; public int Shard; public Mesh MassMesh; public Mesh TreeCardMesh; public Mesh CanopyMesh; public Mesh MountainBiomeMesh; public Mesh SwampBiomeMesh; public int TreePlaneCount; public int CanopyPlaneCount; public int LogicalTreeCardCount; public int CrossedLogicalTreeCardCount; public int SinglePlaneLogicalTreeCardCount; } private sealed class ForestBuildResult { public List Chunks; public int ClusterCount; public int TreeCardCount; public int CanopyCardCount; public float NearestDensity; public int CandidateTotal; public int CandidatesCompleted; public int[] StableCardRecords; public ViewFacingForestOverloadState GeometryOverloadState; } private sealed class ForestChunk { public readonly GameObject Root; public readonly MeshFilter MassFilter; public readonly MeshRenderer MassRenderer; public readonly MeshFilter TreeFilter; public readonly MeshRenderer TreeRenderer; public readonly MeshFilter CanopyFilter; public readonly MeshRenderer CanopyRenderer; public readonly MeshFilter MountainBiomeFilter; public readonly MeshRenderer MountainBiomeRenderer; public readonly MeshFilter SwampBiomeFilter; public readonly MeshRenderer SwampBiomeRenderer; public readonly Vector3 Center; public readonly float Size; public Mesh MassMesh; public Mesh TreeCardMesh; public Mesh CanopyMesh; public Mesh MountainBiomeMesh; public Mesh SwampBiomeMesh; public Bounds WorldBounds; public bool HasBounds; public int LogicalTreeCardCount; public int CrossedLogicalTreeCardCount; public int SinglePlaneLogicalTreeCardCount; public int DetailedRendererCount; public long DetailedVertexCount; public long DetailedTriangleCount; public bool Enabled; public readonly Vector3 CreatedWorldPosition; public readonly Vector3 LocalOrigin; public ForestChunk(int chunkX, int chunkZ, float size, Transform parent, int shard = 0) { //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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) Size = size; Center = new Vector3(((float)chunkX + 0.5f) * size, 0f, ((float)chunkZ + 0.5f) * size); Root = new GameObject("DonegalHorizonForestChunk_" + chunkX + "_" + chunkZ + "_s" + shard); Root.layer = 0; Root.transform.SetParent(parent, false); LocalOrigin = new Vector3((float)chunkX * size, 0f, (float)chunkZ * size); Root.transform.localPosition = LocalOrigin; Root.transform.localRotation = Quaternion.identity; Root.transform.localScale = Vector3.one; CreatedWorldPosition = Root.transform.position; GameObject val = CreateMeshObject("Mass", Root.transform, out MassFilter, out MassRenderer); GameObject val2 = CreateMeshObject("TreeCards", Root.transform, out TreeFilter, out TreeRenderer); GameObject val3 = CreateMeshObject("Canopy", Root.transform, out CanopyFilter, out CanopyRenderer); GameObject val4 = CreateMeshObject("MountainBiomeCards", Root.transform, out MountainBiomeFilter, out MountainBiomeRenderer); GameObject val5 = CreateMeshObject("SwampBiomeCards", Root.transform, out SwampBiomeFilter, out SwampBiomeRenderer); val.transform.localPosition = Vector3.zero; val2.transform.localPosition = Vector3.zero; val3.transform.localPosition = Vector3.zero; val4.transform.localPosition = Vector3.zero; val5.transform.localPosition = Vector3.zero; } public void RecalculateBounds() { //IL_0020: 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_0068: 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_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) HasBounds = false; DetailedRendererCount = 0; DetailedVertexCount = 0L; DetailedTriangleCount = 0L; Bounds combined = default(Bounds); if ((Object)(object)MassMesh != (Object)null) { Encapsulate(ref combined, ref HasBounds, ((Renderer)MassRenderer).bounds); } if ((Object)(object)TreeCardMesh != (Object)null) { Encapsulate(ref combined, ref HasBounds, ((Renderer)TreeRenderer).bounds); AccumulateDetailedMesh(TreeCardMesh); } if ((Object)(object)CanopyMesh != (Object)null) { Encapsulate(ref combined, ref HasBounds, ((Renderer)CanopyRenderer).bounds); AccumulateDetailedMesh(CanopyMesh); } if ((Object)(object)MountainBiomeMesh != (Object)null) { Encapsulate(ref combined, ref HasBounds, ((Renderer)MountainBiomeRenderer).bounds); AccumulateDetailedMesh(MountainBiomeMesh); } if ((Object)(object)SwampBiomeMesh != (Object)null) { Encapsulate(ref combined, ref HasBounds, ((Renderer)SwampBiomeRenderer).bounds); AccumulateDetailedMesh(SwampBiomeMesh); } WorldBounds = combined; if (!HasBounds) { WorldBounds = new Bounds(Center, new Vector3(Size, 1f, Size)); } } private void AccumulateDetailedMesh(Mesh mesh) { if (!((Object)(object)mesh == (Object)null)) { DetailedRendererCount++; DetailedVertexCount += mesh.vertexCount; if (mesh.subMeshCount > 0) { DetailedTriangleCount += (long)mesh.GetIndexCount(0) / 3L; } } } private static void Encapsulate(ref Bounds combined, ref bool has, Bounds bounds) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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) if (!has) { combined = bounds; has = true; } else { ((Bounds)(ref combined)).Encapsulate(bounds); } } public void SetEnabled(bool enabled) { if ((Object)(object)MassRenderer != (Object)null) { ((Renderer)MassRenderer).enabled = enabled && (Object)(object)MassMesh != (Object)null; } if ((Object)(object)TreeRenderer != (Object)null) { ((Renderer)TreeRenderer).enabled = enabled && (Object)(object)TreeCardMesh != (Object)null; } if ((Object)(object)CanopyRenderer != (Object)null) { ((Renderer)CanopyRenderer).enabled = enabled && (Object)(object)CanopyMesh != (Object)null; } if ((Object)(object)MountainBiomeRenderer != (Object)null) { ((Renderer)MountainBiomeRenderer).enabled = enabled && (Object)(object)MountainBiomeMesh != (Object)null; } if ((Object)(object)SwampBiomeRenderer != (Object)null) { ((Renderer)SwampBiomeRenderer).enabled = enabled && (Object)(object)SwampBiomeMesh != (Object)null; } Enabled = enabled; } public void Destroy() { if ((Object)(object)MassMesh != (Object)null) { Object.Destroy((Object)(object)MassMesh); } if ((Object)(object)TreeCardMesh != (Object)null) { Object.Destroy((Object)(object)TreeCardMesh); } if ((Object)(object)CanopyMesh != (Object)null) { Object.Destroy((Object)(object)CanopyMesh); } if ((Object)(object)MountainBiomeMesh != (Object)null) { Object.Destroy((Object)(object)MountainBiomeMesh); } if ((Object)(object)SwampBiomeMesh != (Object)null) { Object.Destroy((Object)(object)SwampBiomeMesh); } if ((Object)(object)Root != (Object)null) { Object.Destroy((Object)(object)Root); } } } private sealed class ForestTile { public readonly GameObject Root; public readonly Vector3 Center; public readonly float Size; public readonly int TileX; public readonly int TileZ; public readonly List Chunks = new List(); public int ClusterCount; public int TreeCardCount; public int CanopyCardCount; public float NearestDensity; public bool PrimaryPassOnly; public bool IsCoverageRepair; public int CandidateTotal; public int CandidatesCompleted; public int[] StableCardRecords; public ViewFacingForestOverloadState GeometryOverloadState; public string GenerationSignatureBase; public bool WasBoundaryBandTile; public float BuiltHBucket; public float BuiltOBucket; public float LastUsedRealtime; public string ContentHash; public int EstimatedVertexCount; public ForestTile(int x, int z, float size, Transform parent) { //IL_0040: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown Size = size; TileX = x; TileZ = z; Center = new Vector3(((float)x + 0.5f) * size, 0f, ((float)z + 0.5f) * size); Root = new GameObject("DonegalHorizonForestTile_" + x + "_" + z); Root.layer = 0; Root.transform.SetParent(parent, false); } public void SetEnabled(bool enabled) { for (int i = 0; i < Chunks.Count; i++) { Chunks[i].SetEnabled(enabled); } } public void ResetForReuse() { //IL_001a: 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_0044: 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_009a: 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_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Root == (Object)null) { return; } Root.transform.localPosition = Vector3.zero; Root.transform.localRotation = Quaternion.identity; Root.transform.localScale = Vector3.one; for (int i = 0; i < Chunks.Count; i++) { ForestChunk forestChunk = Chunks[i]; if (forestChunk != null && !((Object)(object)forestChunk.Root == (Object)null)) { forestChunk.Root.transform.localPosition = forestChunk.LocalOrigin; forestChunk.Root.transform.localRotation = Quaternion.identity; forestChunk.Root.transform.localScale = Vector3.one; for (int j = 0; j < forestChunk.Root.transform.childCount; j++) { Transform child = forestChunk.Root.transform.GetChild(j); child.localPosition = Vector3.zero; child.localRotation = Quaternion.identity; child.localScale = Vector3.one; } forestChunk.SetEnabled(enabled: false); forestChunk.RecalculateBounds(); } } } public void Destroy() { for (int i = 0; i < Chunks.Count; i++) { Chunks[i].Destroy(); } Chunks.Clear(); if ((Object)(object)Root != (Object)null) { Object.Destroy((Object)(object)Root); } } } private sealed class TileRequest { public readonly int X; public readonly int Z; public readonly float Distance; public readonly long Key; public bool IsPrimaryCoverage; public bool IsResident; public TileRequest(int x, int z, float distance, long key, bool isPrimaryCoverage = false) { X = x; Z = z; Distance = distance; Key = key; IsPrimaryCoverage = isPrimaryCoverage; } public static int CompareDistance(TileRequest a, TileRequest b) { return a.Distance.CompareTo(b.Distance); } public static int CompareResidentThenDistance(TileRequest a, TileRequest b) { if (a.IsResident != b.IsResident) { if (!a.IsResident) { return 1; } return -1; } return a.Distance.CompareTo(b.Distance); } } private sealed class ForestAddJob { public readonly int X; public readonly int Z; public readonly long Key; public float Distance; public readonly int Epoch; public readonly float QueuedAtRealtime; public int RetryCount; public bool IsPrimaryCoverage; public bool IsReinforcement; public ForestAddJob(int x, int z, long key, float distance, int epoch, float queuedAtRealtime, bool isPrimaryCoverage = false) { X = x; Z = z; Key = key; Distance = distance; Epoch = epoch; QueuedAtRealtime = queuedAtRealtime; IsPrimaryCoverage = isPrimaryCoverage; } } private struct BetterContinentsMapSettings { public float WorldSize; public float EdgeSize; public float TotalRadius; public float TotalSize; public string ConfigHash; public static BetterContinentsMapSettings CreateDefault(float radius) { BetterContinentsMapSettings result = default(BetterContinentsMapSettings); result.WorldSize = radius - 500f; result.EdgeSize = 500f; result.Recalculate(); result.ConfigHash = "unknown"; return result; } public void Recalculate() { TotalRadius = Mathf.Max(1f, WorldSize + EdgeSize); TotalSize = TotalRadius * 2f; } } public const string PluginGuid = "marc.donegalhorizonlift"; public const string PluginName = "New Horizons Treelines"; public const string PluginVersion = "4.6.31"; private const string BuildName = "Swamp Trees Default Off"; private const string BuildId = "NHT-4.6.31-20260717-SWAMP-TREES-DEFAULT-OFF"; private const float Small = 0.0001f; private const float TreeCardMeshBottomSink = 0.01f; private const float HeightScale = 200f; private const float StandardForestVisibilityChunkSize = 64f; private const int ForestCoverageSectorCount = 16; private const int TreeStartAlgorithmVersion = 5; private const int PresetContractVersion = 5; private const int HandoffFillAlgorithmVersion = 6; private const int GroundingAlgorithmVersion = 10; private const int FinalBiomeRoutingVersion = 3; private const int BudgetSchedulingVersion = 13; private const int ContinuousCoverageAlgorithmVersion = 10; private const int CoverageSectorAlgorithmVersion = 2; private const int MeshAssemblyAlgorithmVersion = 1; private const int AtlasGeometryAlgorithmVersion = 10; private const int AdaptivePerformanceAlgorithmVersion = 2; private const int DeterministicGenerationVersion = 5; private const int StreamingAlgorithmVersion = 6; private const int TreeCardDensityAlgorithmVersion = 1; private const int DistributedDensityAlgorithmVersion = 2; private const int RendererAlgorithmVersion = 3; private const int RendererLodVersion = 2; private const int ViewFacingOverloadGuardVersion = 1; private const int BlackForestScaleVersion = 4; private const int MountainScaleVersion = 2; private const int BlackForestVisibleWidthVersion = 2; private const int CanopyCapContractVersion = 1; private const int ForestMeshCacheSignatureVersion = 1; private const int CompletionSchedulerVersion = 1; private const int TerrainColourSignatureVersion = 1; private const int DiagnosticAlgorithmVersion = 4; private const int GroundingDiagnosticVersion = 1; private const float GoldenBlackForestSupportHeightMultiplier = 1.55f; private const float GoldenBlackForestSupportWidthMultiplier = 2f; private const float GoldenBlackForestSupportMinimumRatio = 0.42f; private const float GoldenBlackForestSupportMaximumRatio = 0.72f; private const float GoldenBlackForestSupportMaximumWidth = 18f; private const float GoldenMountainSupportHeightMultiplier = 1.35f; private const float GoldenMountainSupportWidthMultiplier = 1.2f; private const float GoldenMountainSupportMinimumRandomScale = 0.9f; private const float GoldenMountainSupportMaximumRandomScale = 1.3f; private const float GoldenMountainSupportMinimumRatio = 0.45f; private const float GoldenMountainSupportMaximumRatio = 0.78f; private const float GoldenMountainSupportMaximumQuadWidth = 22f; private const int MaximumDetailedCardsPerRendererChunk = 600; private const int MaximumSinglePlaneCardsPerRendererChunk = 900; private const int MaximumVerticesPerRendererChunk = 24000; private const int Safe16BitTriangleLimit = 20000; private const float CoverageRepairChunkSize = 64f; private const float DefaultMeadowsContinuousCoverage = 1f; private const float DefaultBlackForestContinuousCoverage = 1f; private const float DefaultSwampContinuousCoverage = 0.9f; private const float DefaultMountainContinuousCoverage = 0.9f; private const float DefaultPlainsContinuousCoverage = 0.2f; private const string DefaultProfileDir = "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Valheim_Modded_BACKUP\\DonegalValheimYourThirsty\\Valheim\\profiles\\DonegalHorizons"; private const int PresetMaximumTerrainTileCeiling = 800; private const int PresetMaximumForestTileCeiling = 2800; private static readonly PresetRuntimeProfile VeryLowRuntimeProfile = CreatePresetRuntimeProfile(QualityPreset.VeryLow, "VeryLow", 500f, useWorldMaximum: false, 220, 50000, 35000, 700, 2, 2); private static readonly PresetRuntimeProfile LowRuntimeProfile = CreatePresetRuntimeProfile(QualityPreset.Low, "Low", 1000f, useWorldMaximum: false, 320, 70000, 50000, 950, 2, 2); private static readonly PresetRuntimeProfile BalancedRuntimeProfile = CreatePresetRuntimeProfile(QualityPreset.Balanced, "Balanced", 2000f, useWorldMaximum: false, 500, 100000, 75000, 1400, 3, 3); private static readonly PresetRuntimeProfile MediumRuntimeProfile = CreatePresetRuntimeProfile(QualityPreset.Medium, "Medium", 4000f, useWorldMaximum: false, 800, 140000, 105000, 2100, 4, 3); private static readonly PresetRuntimeProfile HighRuntimeProfile = CreatePresetRuntimeProfile(QualityPreset.High, "High", 7000f, useWorldMaximum: false, 1400, 190000, 145000, 3000, 5, 4); private static readonly PresetRuntimeProfile UltraRuntimeProfile = CreatePresetRuntimeProfile(QualityPreset.Ultra, "Ultra", 10000f, useWorldMaximum: false, 2600, 260000, 195000, 4000, 6, 5); private static readonly PresetRuntimeProfile HorizonRuntimeProfile = CreatePresetRuntimeProfile(QualityPreset.Horizon, "Horizon", 0f, useWorldMaximum: true, 2800, 340000, 255000, 5000, 7, 6); private static readonly TreeCardDensityProfile GoldenHighDensityProfile = new TreeCardDensityProfile { Preset = TreeCardDensityPreset.High, ClusterCellSize = 18f, DensityThreshold = 0f, DensityMultiplier = 13.036f, CandidateTotal = 900, CandidateStep = 48, MaximumClusters = 6799, MaximumTreePlanes = 10945, MeadowsCoverage = 1f, BlackForestCoverage = 1f, NearRetention = 1f, MidRetention = 1f, FarRetention = 0.85f, HorizonRetention = 0.7f, HandoffGap = 18f, NearGap = 22f, MidGap = 30f, FarGap = 42f, HorizonGap = 60f, GlobalDistributedDensity = 1.65f, BlackForestDistributedDensity = 2f, MeadowsDistributedDensity = 1.3f, MountainDistributedDensity = 1.15f, PlainsDistributedDensity = 0.25f, HardRejectSlope = 52.366f }; private ConfigEntry _enabled; private ConfigEntry _waitForGameplayWorld; private ConfigEntry _requireWaterSystemForProceduralWorld; private ConfigEntry _worldDataMode; private ConfigEntry _proceduralWorldRadius; private ConfigEntry _mapFolder; private ConfigEntry _betterContinentsConfigFile; private ConfigEntry _renderLimitsConfigFile; private ConfigEntry _heightMapFile; private ConfigEntry _colourMapFile; private ConfigEntry _forestMapFile; private ConfigEntry _treeAtlasFile; private ConfigEntry _canopyAtlasFile; private ConfigEntry _mountainBiomeAtlasFile; private ConfigEntry _swampBiomeAtlasFile; private ConfigEntry _requireRenderLimits; private ConfigEntry _allowManualEnvelopeWithoutRenderLimits; private ConfigEntry _manualNearWorldExclusionRadius; private ConfigEntry _minimumNearWorldExclusionRadius; private ConfigEntry _nativeEnvelopePadding; private ConfigEntry _qualityPreset; private ConfigEntry _autoDetectNativeTreeViewDistance; private ConfigEntry _nativeTreeViewDistanceFallback; private ConfigEntry _nativeTreelineMode; private ConfigEntry _nativeTreelineCalibratedRadius; private ConfigEntry _nativeTreelineSeamOverlap; private ConfigEntry _enforceStrictCalibratedTreeline; private ConfigEntry _nativeTreelineSeamFadeWidth; private ConfigEntry _nativeTreelineSeamTolerance; private ConfigEntry _nativeTreelineHandoffOffset; private ConfigEntry _nativeTreelineBoundaryChunkSize; private ConfigEntry _normalForestChunkSize; private ConfigEntry _canopyHandoffOffset; private ConfigEntry _enableHandoffFill; private ConfigEntry _handoffFillBandWidth; private ConfigEntry _handoffFillMinimumCoverage; private ConfigEntry _handoffFillCandidateSpacing; private ConfigEntry _handoffFillMaximumGap; private ConfigEntry _handoffFillUsesBiomeDensity; private ConfigEntry _handoffFillRequiresValidForestLand; private ConfigEntry _enableContinuousForestCoverage; private ConfigEntry _continuousMeadowsCoverage; private ConfigEntry _continuousBlackForestCoverage; private ConfigEntry _continuousSwampCoverage; private ConfigEntry _continuousMountainCoverage; private ConfigEntry _continuousPlainsCoverage; private ConfigEntry _continuousMistlandsCoverage; private ConfigEntry _continuousAshlandsCoverage; private ConfigEntry _continuousDeepNorthCoverage; private ConfigEntry _continuousNearGridRetention; private ConfigEntry _continuousMidGridRetention; private ConfigEntry _continuousFarGridRetention; private ConfigEntry _continuousHorizonGridRetention; private ConfigEntry _coverageHandoffMaximumGap; private ConfigEntry _coverageNearMaximumGap; private ConfigEntry _coverageMidMaximumGap; private ConfigEntry _coverageFarMaximumGap; private ConfigEntry _coverageHorizonMaximumGap; private ConfigEntry _coverageRepairRecoveryRadius; private ConfigEntry _coverageRepairMaxRetries; private ConfigEntry _coverageRepairJobsPerFrame; private ConfigEntry _coverageCellsPerResumableStep; private ConfigEntry _maximumActiveCoverageAuditJobs; private ConfigEntry _maximumCoverageRepairJobsAdmittedPerFrame; private ConfigEntry _maximumCoverageRepairCardsCommittedPerFrame; private ConfigEntry _maximumCoverageSectorStarvationSeconds; private ConfigEntry _coastalDryLandSearchRadius; private ConfigEntry _coastalSearchMaximumAttempts; private ConfigEntry _coastalSearchAttemptsPerResumableStep; private ConfigEntry _coastalSearchAngularSamples; private ConfigEntry _enableCoastalLandRecovery; private ConfigEntry _coastalLandRecoveryRadius; private ConfigEntry _coastalLandRecoveryAttempts; private ConfigEntry _blackForestNearMinimumSubclusters; private ConfigEntry _meadowsNearMinimumSubclusters; private ConfigEntry _allowDetailedTreeFoliageOverhangAtCoast; private ConfigEntry _coastalDetailedTreeWaterSafetyWidth; private ConfigEntry _coastalDetailedTreeNearWaterRejectRadius; private ConfigEntry _coastalDetailedTreeMinimumAboveWater; private ConfigEntry _treeCardDensityPreset; private ConfigEntry _preserveExistingManualTreeCardValues; private ConfigEntry _autoMatchTreeDensityToQualityPreset; private ConfigEntry _globalDistributedTreeDensity; private ConfigEntry _blackForestDistributedDensity; private ConfigEntry _meadowsDistributedDensity; private ConfigEntry _swampDistributedDensity; private ConfigEntry _mountainDistributedDensity; private ConfigEntry _plainsDistributedDensity; private ConfigEntry _newHorizonsExtensionDistance; private ConfigEntry _forestContinuityEnabled; private ConfigEntry _enableFarTerrain; private ConfigEntry _continuityStartDistance; private ConfigEntry _decoupleForestStartFromTerrainExclusion; private ConfigEntry _minimumForestStartDistance; private ConfigEntry _forestExclusionMarginScale; private ConfigEntry _continuityEndDistance; private ConfigEntry _treeCardEndDistance; private ConfigEntry _canopyStartDistance; private ConfigEntry _continuityTileSize; private ConfigEntry _continuityRebuildDistance; private ConfigEntry _nearCullHysteresis; private ConfigEntry _clusterCellSize; private ConfigEntry _forestDensityThreshold; private ConfigEntry _forestDensityMultiplier; private ConfigEntry _slopeRejectionThreshold; private ConfigEntry _hardSlopeRejectionThreshold; private ConfigEntry _maximumClustersPerTile; private ConfigEntry _maxTreeCardPlanesPerTile; private ConfigEntry _maxCanopyPlanesPerTile; private ConfigEntry _slopeSampleRadius; private ConfigEntry _innerTerrainDistance; private ConfigEntry _farTerrainViewDistance; private ConfigEntry _farTerrainTileSize; private ConfigEntry _farTerrainMeshResolution; private ConfigEntry _farForestStartDistance; private ConfigEntry _farForestEndDistance; private ConfigEntry _forestTerrainTintStrength; private ConfigEntry _forestTerrainTintColour; private ConfigEntry _useBetterContinentsExactSampler; private ConfigEntry _verticalOffset; private ConfigEntry _extendMainCameraFarClip; private ConfigEntry _mainCameraFarClip; private ConfigEntry _tilesBuiltPerFrame; private ConfigEntry _cullBehindCamera; private ConfigEntry _behindCameraDot; private ConfigEntry _maxTerrainTiles; private ConfigEntry _maxForestTiles; private ConfigEntry _panicTileCeiling; private ConfigEntry _globalTreeCardPlaneBudget; private ConfigEntry _globalCanopyPlaneBudget; private ConfigEntry _enableRingBudgetReservation; private ConfigEntry _handoffMinimumTreeBudgetShare; private ConfigEntry _nearMinimumTreeBudgetShare; private ConfigEntry _midMinimumTreeBudgetShare; private ConfigEntry _farMinimumTreeBudgetShare; private ConfigEntry _horizonMinimumTreeBudgetShare; private ConfigEntry _handoffMinimumCanopyBudgetShare; private ConfigEntry _nearMinimumCanopyBudgetShare; private ConfigEntry _midMinimumCanopyBudgetShare; private ConfigEntry _farMinimumCanopyBudgetShare; private ConfigEntry _horizonMinimumCanopyBudgetShare; private ConfigEntry _allowUnusedRingBudgetRedistribution; private ConfigEntry _nearHandoffMinimumAlpha; private ConfigEntry _midDistanceMinimumAlpha; private ConfigEntry _farDistanceMinimumAlpha; private ConfigEntry _horizonMinimumAlpha; private ConfigEntry _enableIncrementalForestStreaming; private ConfigEntry _forestGenerationTimeBudgetMs; private ConfigEntry _maxMeshUploadsPerFrame; private ConfigEntry _maxChunkActivationsPerFrame; private ConfigEntry _pauseGenerationAboveFrameTimeMs; private ConfigEntry _slowFrameGenerationBudgetMs; private ConfigEntry _streamingRecalculateDistance; private ConfigEntry _sliderRebuildDebounceSeconds; private ConfigEntry _forestRetirementTimeBudgetMs; private ConfigEntry _maxChunkDestructionsPerFrame; private ConfigEntry _maxForestJobRetries; private ConfigEntry _maximumCandidateCellsPerTileBuild; private ConfigEntry _candidateEvaluationsPerResumableStep; private ConfigEntry _enableAdaptiveForestGenerationBudget; private ConfigEntry _normalForestGenerationCpuBudgetMs; private ConfigEntry _stationaryForestGenerationCpuBudgetMs; private ConfigEntry _movementPressureForestGenerationCpuBudgetMs; private ConfigEntry _startupForestGenerationCpuBudgetMs; private ConfigEntry _generationTargetFrameTimeMs; private ConfigEntry _generationBudgetRecoveryDelaySeconds; private ConfigEntry _terrainGroundSamplesPerResumableStep; private ConfigEntry _footprintValidationsPerResumableStep; private ConfigEntry _slopeValidationsPerResumableStep; private ConfigEntry _cardsAppendedToMeshPerResumableStep; private ConfigEntry _maximumSimultaneousMeshAssemblyJobs; private ConfigEntry _maximumCompletedForestTileCommitsPerFrame; private ConfigEntry _repairChunkRebuildCoalescingSeconds; private ConfigEntry _maximumAdmittedForestGenerationJobs; private ConfigEntry _hardCandidateEvaluationCeiling; private ConfigEntry _maximumForestTileBuildsPerFrameSafetyCap; private ConfigEntry _enableStartupHitchGuard; private ConfigEntry _startupInitialDelaySeconds; private ConfigEntry _startupSafeModeSeconds; private ConfigEntry _startupForestBuildIntervalFrames; private ConfigEntry _startupTerrainBuildIntervalFrames; private ConfigEntry _runExpensiveDeterministicStartupSelfTest; private ConfigEntry _coverageRepairTimeBudgetMs; private ConfigEntry _coverageRepairHardJobsPerFrame; private ConfigEntry _minimumActiveChunksBeforeCoverageRepair; private ConfigEntry _minimumMovementSyncIntervalSeconds; private ConfigEntry _fastMovementRebuildDistance; private ConfigEntry _maximumMovementSyncsPerSecond; private ConfigEntry _enableForestObjectPooling; private ConfigEntry _maxPooledForestChunks; private ConfigEntry _maxPooledMeshes; private ConfigEntry _clearPoolsOnWorldChange; private ConfigEntry _enableForestMemoryCache; private ConfigEntry _forestMemoryCacheLimitMb; private ConfigEntry _maxCachedForestChunks; private ConfigEntry _cacheRetentionDistance; private ConfigEntry _forestPreloadDistance; private ConfigEntry _forestChunkRetentionDistance; private ConfigEntry _forestFarChunkMergeEnabled; private ConfigEntry _midForestChunkSize; private ConfigEntry _forestFarChunkSize; private ConfigEntry _forestFarChunkMergeStart; private ConfigEntry _forestVeryFarChunkMergeEnabled; private ConfigEntry _forestVeryFarChunkSize; private ConfigEntry _forestVeryFarChunkMergeStart; private ConfigEntry _minimumTreeMaterialUpdateIntervalSeconds; private ConfigEntry _minimumBrightnessChangeBeforeUpdate; private ConfigEntry _visibilityUpdateIntervalSeconds; private ConfigEntry _enableFarSinglePlaneLod; private ConfigEntry _farSinglePlaneLodStartDistance; private ConfigEntry _horizonSinglePlaneLodStartDistance; private ConfigEntry _enableViewFacingForestOverloadGuard; private ConfigEntry _visibleDetailedTriangleSoftLimit; private ConfigEntry _visibleDetailedTriangleHardLimit; private ConfigEntry _visibleTreeRendererSoftLimit; private ConfigEntry _visibleTreeRendererHardLimit; private ConfigEntry _enableAdaptiveHighPresetGovernor; private ConfigEntry _adaptiveTargetFrameTimeMs; private ConfigEntry _adaptiveSoftFrameTimeMs; private ConfigEntry _adaptiveHardFrameTimeMs; private ConfigEntry _adaptiveFrameSmoothingSamples; private ConfigEntry _adaptiveRecoveryDelaySeconds; private ConfigEntry _adaptiveRecoveryRatePerSecond; private ConfigEntry _adaptiveMinimumGenerationBudgetMs; private ConfigEntry _adaptiveMinimumMeshUploadsPerFrame; private ConfigEntry _adaptiveMinimumChunkActivationsPerFrame; private ConfigEntry _adaptiveHardSpikeCooldownSeconds; private ConfigEntry _adaptiveMaximumBuildOverrunCooldownSeconds; private ConfigEntry _adaptiveReinforcementDeferPressure; private ConfigEntry _bootstrapPrimaryGenerationBudgetMs; private ConfigEntry _minimumPrimaryProgressStepsPerFrame; private ConfigEntry _maximumPrimaryStarvationSeconds; private ConfigEntry _maximumReinforcementStarvationSeconds; private ConfigEntry _minimumReinforcementProgressStepsAfterStarvation; private ConfigEntry _maximumCoverageStarvationSeconds; private ConfigEntry _minimumCoverageProgressStepsAfterStarvation; private ConfigEntry _maximumDesiredTileStarvationSeconds; private ConfigEntry _bootstrapMeshUploadsPerFrame; private ConfigEntry _enablePredictiveStreamingPriority; private ConfigEntry _predictiveMovementPriorityStrength; private ConfigEntry _predictiveCameraPriorityStrength; private ConfigEntry _adaptiveTerrainBuildIntervalFrames; private ConfigEntry _terrainSlopeShadingStrength; private ConfigEntry _terrainDistanceTintStrength; private ConfigEntry _enableHorizonClarity; private ConfigEntry _reduceHorizonHaze; private ConfigEntry _horizonHazeStrength; private ConfigEntry _terrainDistanceFadeStrength; private ConfigEntry _forestDistanceFadeStrength; private ConfigEntry _farTerrainContrast; private ConfigEntry _farForestContrast; private ConfigEntry _farForestDarkness; private ConfigEntry _farTerrainDarkness; private ConfigEntry _farTreeAlpha; private ConfigEntry _farCanopyAlpha; private ConfigEntry _preserveWeatherFog; private ConfigEntry _weatherFogInfluence; private ConfigEntry _clearWeatherVisibilityBoost; private ConfigEntry _mistWeatherVisibilityBoost; private ConfigEntry _stormWeatherVisibilityBoost; private string _lastClarityWeather = ""; private ConfigEntry _hazeControlMode; private ConfigEntry _clearWeatherHazeMultiplier; private ConfigEntry _lightCloudHazeMultiplier; private ConfigEntry _maximumHazeReduction; private ConfigEntry _hazeBlendSpeed; private ConfigEntry _enableRealClearSkies; private ConfigEntry _clearSkiesStrength; private ConfigEntry _clearSkiesOperatingMode; private ConfigEntry _allowOccasionalCrystalClearWeather; private ConfigEntry _crystalClearChancePerClearDay; private ConfigEntry _crystalClearMinimumDurationMinutes; private ConfigEntry _crystalClearMaximumDurationMinutes; private ConfigEntry _crystalClearFogMultiplier; private ConfigEntry _crystalClearHorizonHazeMultiplier; private ConfigEntry _crystalClearCloudOpacityMultiplier; private ConfigEntry _crystalClearDistanceTintMultiplier; private ConfigEntry _clearWeatherFogMultiplier; private ConfigEntry _clearWeatherHorizonHazeMultiplier; private ConfigEntry _clearWeatherCloudOpacityMultiplier; private ConfigEntry _clearWeatherDistanceTintMultiplier; private ConfigEntry _clearSkiesTransitionSeconds; private ConfigEntry _preserveStormWeather; private ConfigEntry _preserveRainAndSnow; private ConfigEntry _preserveMistlandsMist; private ConfigEntry _preserveAshlandsAtmosphere; private ConfigEntry _preserveDeepNorthAtmosphere; private ConfigEntry _preserveBossWeather; private ConfigEntry _restoreOriginalWeatherValuesOnDisable; private bool _crystalClearEventActive; private float _crystalClearEventEndRealtime = -1f; private int _crystalClearScheduledForDay = int.MinValue; private float _crystalClearEventRemainingSecondsForDiagnostics; private ConfigEntry _waterSurfaceMode; private ConfigEntry _waterSurfaceHeightOverride; private ConfigEntry _waterClearance; private ConfigEntry _shoreSampleRadius; private ConfigEntry _reloadKey; private ConfigEntry _alternateReloadKey; private ConfigEntry _enableCalibrationMode; private ConfigEntry _calibrationToggleKey; private ConfigEntry _calibrationIncrease1mKey; private ConfigEntry _calibrationDecrease1mKey; private ConfigEntry _calibrationIncrease5mKey; private ConfigEntry _calibrationDecrease5mKey; private ConfigEntry _calibrationIncrease25mKey; private ConfigEntry _calibrationDecrease25mKey; private ConfigEntry _calibrationSaveKey; private ConfigEntry _calibrationResetKey; private ConfigEntry _calibrationRecordSampleKey; private ConfigEntry _calibrationClearSamplesKey; private ConfigEntry _calibrationGuideLineWidth; private ConfigEntry _calibrationGuideHeightOffset; private ConfigEntry _calibrationGuidePointCountConfig; private ConfigEntry _showCalibrationVerticalMarkers; private ConfigEntry _calibrationMarkerHeight; private ConfigEntry _calibrationGuideAlwaysVisible; private ConfigEntry _showCalibrationTestGuide; private ConfigEntry _calibrationTestGuideRadius; private ConfigEntry _enableProxyForestMasses; private ConfigEntry _enableProxyMassesInSwamp; private ConfigEntry _swampTreeCardStartDistance; private ConfigEntry _swampTreeCardEndDistance; private ConfigEntry _swampNearCardDensityMultiplier; private ConfigEntry _swampMidCardDensityMultiplier; private long _closeSwampRejectedWater; private long _closeSwampRejectedRoot; private long _closeSwampEmitted; private Biome _lastValidationBiome; private long _swampNoFloatAttempts; private long _swampPassedDensity; private long _swampRejectedThreshold; private long _swampRejectedSlope; private long _swampRejectedWater; private long _swampRejectedVisibleLandRatio; private long _swampRejectedCoastline; private long _swampRejectedSupport; private long _swampRejectedRootAnchor; private long _swampRejectedRootDryRatio; private long _swampRejectedWaterChannel; private long _swampRejectedFinalFloating; private int _swampChunksBuilt; private int _swampRenderersCreated; private int _swampRenderersEnabled; private int _swampInnerCulled; private int _swampOuterCulled; private bool _staticPlacementOk = true; private int _debugPageIndex; private float _lastRebuildStartTime; private float _lastRebuildDurationSeconds; private bool _rebuildTimingPending; private long _proxyAttempts; private long _proxyAttemptsBlockedDisabled; private long _proxyAttemptsBlockedSwamp; private long _treeSampleRetriesUsed; private GroundRejectReason _lastNoFloatRejectReason; private ConfigEntry _enableHardcodedReloadFallbacks; private ConfigEntry _debugKey; private ConfigEntry _showDebug; private ConfigEntry _forestProofDiagnostic; private ConfigEntry _debugDrawCardBases; private ConfigEntry _groundAuthoritativePlacement; private ConfigEntry _requireExactFootprintTerrainSupport; private ConfigEntry _rejectAnyFootprintSampleWater; private ConfigEntry _rejectAnyFootprintSampleUnsupported; private ConfigEntry _maxFootprintHeightDifference; private ConfigEntry _defaultMinimumLandAboveWater; private ConfigEntry _plainsMinimumLandAboveWater; private ConfigEntry _coastalMinimumLandAboveWater; private ConfigEntry _swampMinimumLandAboveWater; private ConfigEntry _nonSwampNearWaterRejectRadius; private ConfigEntry _swampNearWaterRejectRadius; private ConfigEntry _swampMaxCanopyCardWidth; private ConfigEntry _swampMaxProxyCardWidth; private ConfigEntry _requireFinalSwampPositionRemainsSwamp; private ConfigEntry _maxSwampInlandRetryDistance; private ConfigEntry _rejectSwampCardIfNoValidGround; private ConfigEntry _swampFinalRootEmbedDepth; private ConfigEntry _swampMaxFinalFloatingClearance; private ConfigEntry _debugSwampCardTypeColours; private ConfigEntry _enableCrossBiomeDuplicateRejection; private ConfigEntry _duplicateHorizontalDistanceTolerance; private ConfigEntry _duplicateBaseHeightDifferenceWarning; private ConfigEntry _duplicateFootprintOverlapThreshold; private ConfigEntry _maxFinalGroundFloatingError; private ConfigEntry _maxFinalGroundBurialError; private ConfigEntry _maxGroundHeightVarianceStandardCard; private ConfigEntry _maxGroundHeightVarianceLargeCard; private ConfigEntry _enableStrictFinalHeightmapValidation; private ConfigEntry _finalRootEmbedDepth; private ConfigEntry _minimumRootSupportRatio; private ConfigEntry _minimumFootprintSupportRatio; private ConfigEntry _maximumUnsupportedSpan; private ConfigEntry _maximumStandardGroundCardWidth; private ConfigEntry _maximumSwampGroundCardWidth; private ConfigEntry _maximumPlainsGroundCardWidth; private ConfigEntry _treeCardVerticalAdjustment; private ConfigEntry _mixedVerticalAdjustment; private ConfigEntry _blackForestVerticalAdjustment; private ConfigEntry _swampVerticalAdjustmentFinal; private ConfigEntry _mountainVerticalAdjustmentFinal; private ConfigEntry _plainsVerticalAdjustmentFinal; private ConfigEntry _maximumProxyGroundMassWidth; private ConfigEntry _rejectGroundCardsOverOpenWater; private ConfigEntry _splitLargeCardsOnUnevenTerrain; private ConfigEntry _meadowsDistantTreeDensity; private ConfigEntry _blackForestDistantTreeDensity; private ConfigEntry _swampDistantTreeDensity; private ConfigEntry _mountainDistantTreeDensity; private ConfigEntry _plainsDistantTreeDensity; private ConfigEntry _mistlandsDistantTreeDensity; private ConfigEntry _ashlandsDistantTreeDensity; private ConfigEntry _deepNorthDistantTreeDensity; private ConfigEntry _meadowsDistantCanopyDensity; private ConfigEntry _blackForestDistantCanopyDensity; private ConfigEntry _swampDistantCanopyDensity; private ConfigEntry _mountainDistantCanopyDensity; private ConfigEntry _plainsDistantCanopyDensity; private ConfigEntry _mistlandsDistantCanopyDensity; private ConfigEntry _daylightTreeBrightness; private ConfigEntry _sunsetTreeBrightness; private ConfigEntry _nightTreeBrightness; private ConfigEntry _overcastTreeBrightness; private ConfigEntry _stormTreeBrightness; private ConfigEntry _minimumTreeLuminance; private ConfigEntry _naturalDaylightDarkening; private ConfigEntry _biomeColourPreservation; private ConfigEntry _weatherColourInfluence; private ConfigEntry _lateAfternoonTreeBrightness; private ConfigEntry _twilightTreeBrightness; private ConfigEntry _moonlitNightTreeBrightness; private ConfigEntry _lightingTransitionSeconds; private ConfigEntry _midDistanceOriginalColourStrength; private ConfigEntry _farDistanceOriginalColourStrength; private ConfigEntry _farDistanceAtmosphericInfluence; private float _lastAmbientLuminanceForDiagnostics; private float _lastSunElevationForDiagnostics; private float _lastDaylightFactorForDiagnostics; private float _lastTreeBrightnessForDiagnostics = 1f; private float _smoothedTreeBrightness = 1f; private float _lastAppliedTreeBrightness = -1f; private bool _treeLightingBlendInitialized; private float _lastTreeLightingApplyRealtime = -1f; private ConfigEntry _preserveOriginalColourNearHandoff; private ConfigEntry _nearHandoffColourBandWidth; private ConfigEntry _nearHandoffDaylightOriginalColourStrength; private ConfigEntry _nearHandoffWeatherColourInfluence; private ConfigEntry _nearHandoffFogColourInfluence; private ConfigEntry _nearHandoffMinimumDaylightBrightness; private ConfigEntry _nearHandoffMaximumDaylightBrightness; private ConfigEntry _useNeutralAtlasNormals; private MaterialPropertyBlock _treeRendererPropertyBlock; private readonly Dictionary _treeRendererPropertyStates = new Dictionary(); private long _treeMaterialUpdatePasses; private long _treeMaterialUpdatesSkippedByInterval; private long _treeMaterialUpdatesSkippedByBrightness; private long _treePropertyBlockWrites; private bool _treeRendererPropertiesDirty = true; private int _nearHandoffChunksTinted; private float _lastNearHandoffBrightnessForDiagnostics = 1f; private ConfigEntry _enableTrueColourDistantLand; private ConfigEntry _clearWeatherOriginalTerrainColourStrength; private ConfigEntry _clearWeatherAtmosphericColourStrength; private ConfigEntry _clearWeatherMaximumTerrainDarkening; private ConfigEntry _clearWeatherDistantSaturationStrength; private ConfigEntry _radialTerrainColourTransitionWidth; private ConfigEntry _trueColourBlendSeconds; private ConfigEntry _useFullResolutionProviderTerrainColour; private ConfigEntry _useUntintedProviderTerrainColourMap; private ConfigEntry _fallbackTerrainColourTextureResolution; private ConfigEntry _preserveNativeTerrainLodSystemTrueColour; private ConfigEntry _preserveStormTerrainAtmosphere; private ConfigEntry _preserveNightTerrainDarkness; private ConfigEntry _preserveSunriseAndSunsetColourTrueColour; private ConfigEntry _preserveSpecialBiomeAtmosphereTerrain; private ConfigEntry _trueColourDiagnosticTarget; private ConfigEntry _enableSwampTreeCards; private ConfigEntry _swampTreeDensityMultiplier; private ConfigEntry _swampFootprintRadiusScale; private ConfigEntry _swampMaxFootprintHeightDiff; private ConfigEntry _swampAllowShallowWetGround; private ConfigEntry _swampMaxShallowWaterDepth; private ConfigEntry _minimumSwampBiomeFootprintRatio; private ConfigEntry _minimumSwampRootSupportRatio; private ConfigEntry _minimumSwampFootprintSupportRatio; private ConfigEntry _swampSinkIntoGround; private ConfigEntry _swampTreeHeightMultiplier; private ConfigEntry _swampTreeWidthMultiplier; private ConfigEntry _enableMountainTreeCards; private ConfigEntry _mountainTreeDensityMultiplier; private ConfigEntry _mountainMaximumSlope; private ConfigEntry _mountainMinimumHeight; private ConfigEntry _mountainFootprintRadiusScale; private ConfigEntry _mountainMaxFootprintHeightDiff; private ConfigEntry _mountainSinkIntoGround; private ConfigEntry _mountainTreeHeightMultiplier; private ConfigEntry _mountainTreeWidthMultiplier; private ConfigEntry _mountainMinimumRandomScale; private ConfigEntry _mountainMaximumRandomScale; private ConfigEntry _mountainMinimumWidthToHeightRatio; private ConfigEntry _mountainMaximumWidthToHeightRatio; private ConfigEntry _mountainMinimumAutomaticWidthScale; private ConfigEntry _maximumMountainGroundCardWidth; private ConfigEntry _blackForestTreeHeightMultiplier; private ConfigEntry _blackForestTreeWidthMultiplier; private ConfigEntry _blackForestPineHeightMultiplier; private ConfigEntry _blackForestPineWidthMultiplier; private ConfigEntry _blackForestPineMinimumRandomScale; private ConfigEntry _blackForestPineMaximumRandomScale; private ConfigEntry _blackForestMinimumRandomScale; private ConfigEntry _blackForestMaximumRandomScale; private ConfigEntry _blackForestMinimumWidthToHeightRatio; private ConfigEntry _blackForestMaximumWidthToHeightRatio; private ConfigEntry _maximumBlackForestGroundCardWidth; private ConfigEntry _blackForestMinimumAutomaticWidthScale; private ConfigEntry _enableSlopeAwareCardGrounding; private ConfigEntry _maxVisibleEdgeFloatingError; private ConfigEntry _maxVisibleEdgeBurialError; private ConfigEntry _maxStandardFootprintVariation; private ConfigEntry _maxMountainFootprintVariation; private ConfigEntry _minimumAutomaticWidthScale; private ConfigEntry _enableAutomaticWidthReduction; private ConfigEntry _enableSlopeCardSplitting; private ConfigEntry _maximumSplitAttempts; private ConfigEntry _enablePlainsSparseTreeCards; private ConfigEntry _plainsTreeDensityMultiplier; private ConfigEntry _plainsTreeHeightMultiplier; private ConfigEntry _plainsTreeWidthMultiplier; private ConfigEntry _mixedCandidateDensityFloor; private ConfigEntry _swampCandidateDensityFloor; private ConfigEntry _mountainCandidateDensityFloor; private ConfigEntry _plainsCandidateDensityFloor; private ConfigEntry _enableCardGroundLock; private ConfigEntry _cardBaseHeightMode; private ConfigEntry _maxCardBaseAboveGround; private ConfigEntry _rejectIfFinalBaseFloats; private ConfigEntry _finalBaseFloatTolerance; private ConfigEntry _rejectIfTerrainSupportUncertain; private ConfigEntry _rejectDistantUnsupportedCards; private ConfigEntry _applyGroundLockToTreeCards; private ConfigEntry _applyGroundLockToBiomeCards; private ConfigEntry _applyGroundLockToProxyForests; private ConfigEntry _applyGroundLockToCanopyCards; private ConfigEntry _applyGroundLockToFillCards; private ConfigEntry _enableVisibleLandSupportGate; private ConfigEntry _rejectCardsBelowWaterSurface; private ConfigEntry _minimumVisibleLandSamples; private ConfigEntry _requiredVisibleLandSampleRatio; private ConfigEntry _minimumBaseAboveWater; private ConfigEntry _swampMinimumBaseAboveWater; private ConfigEntry _rejectOpenWaterCards; private ConfigEntry _rejectCoastlineEdgeFloaters; private ConfigEntry _coastlineVisibleLandSampleRatio; private ConfigEntry _distantCardsRequireExactVisibleLandSupport; private ConfigEntry _rejectIfWaterBetweenSamples; private ConfigEntry _failClosedIfSupportUncertain; private ConfigEntry _enableTrunkAnchorGrounding; private ConfigEntry _rootAnchorMode; private ConfigEntry _rootAnchorForwardOffset; private ConfigEntry _rootAnchorSideOffset; private ConfigEntry _rootAnchorSampleRadius; private ConfigEntry _rootAnchorExtraSamples; private ConfigEntry _rootAnchorMinimumSamples; private ConfigEntry _rootAnchorRequiredDryRatio; private ConfigEntry _rootAnchorMaximumAboveGround; private ConfigEntry _rootAnchorFloatTolerance; private ConfigEntry _rejectIfRootAnchorBelowWater; private ConfigEntry _rejectIfRootAnchorUnsupported; private ConfigEntry _rejectIfRootAnchorOverWaterChannel; private ConfigEntry _applyRootToMixedTreeCards; private ConfigEntry _applyRootToSwampTreeCards; private ConfigEntry _applyRootToMountainTreeCards; private ConfigEntry _applyRootToPlainsTreeCards; private ConfigEntry _applyRootToFillTreeCards; private ConfigEntry _swampRootAnchorMinimumBaseAboveWater; private ConfigEntry _swampRootAnchorRequiredDryRatio; private ConfigEntry _swampRejectRootNearOpenWater; private ConfigEntry _swampRootWaterChannelProbeRadius; private long _groundLockLowered; private long _groundLockRejectedFloat; private long _groundLockRejectedDistantUnsupported; private long _groundLockRejectedProxy; private long _groundLockRejectedCanopy; private long _groundLockRejectedTree; private long _noFloatPlacementsAttempted; private long _noFloatPlacementsAccepted; private long _noFloatRejectedBelowWater; private long _noFloatRejectedVisibleLandRatio; private long _noFloatRejectedCoastlineEdge; private long _noFloatRejectedUncertainSupport; private long _noFloatRejectedFinalFloating; private long _noFloatCardsSunkIntoGround; private long _postLockLiftDetectedCount; private long _noFloatRejectedTreeBiome; private long _noFloatRejectedCanopy; private long _noFloatRejectedProxyMass; private long _noFloatRejectedFillDuplicate; private long _treeBiomeNoFloatAttempts; private long _treeBiomeNoFloatValidated; private long _treeBiomeRejectedNoFloating; private long _treeBiomeRejectedValidationMissing; private long _treeBiomeRejectedBelowWater; private long _treeBiomeRejectedVisibleLandRatio; private long _treeBiomeRejectedAfterMeshGuard; private long _addAtlasCardBlockedCount; private long _postValidationLiftBlockedCount; private long _rootAnchorAttempts; private long _rootAnchorAccepted; private long _rootAnchorRejectedWater; private long _rootAnchorRejectedUnsupported; private long _rootAnchorRejectedDryRatio; private long _rootAnchorRejectedFloatHeight; private long _rootAnchorRejectedWaterChannel; private long _rootAnchorMissingValidationBlocked; private long _swampRootAccepted; private long _swampRootRejected; private long _mountainRootAccepted; private long _mountainRootRejected; private long _plainsRootAccepted; private long _plainsRootRejected; private long _mixedRootAccepted; private long _mixedRootRejected; private long _treeCardMeshGuardBlockedRootMissing; private long _treeCardMeshBottomCorrected; private long _treeCardPostRootLiftBlocked; private int _placementValidationEpoch; private long _nextPlacementValidationId; private int _debugCardBaseLogsThisRebuild; private long _swampCandidates; private long _swampChunksFreshlyBuilt; private long _swampChunksRestoredFromCache; private long _swampChunksPoolReused; private long _swampCacheTransformMismatches; private long _swampPoolResetFailures; private long _swampMeshCoordinateViolations; private float _swampMaxCoordinateErrorMeters; private long _swampRejectedOceanEdge; private long _swampRejectedExcessiveSpan; private string _lastSwampFloatingChunkKey = "none"; private readonly Dictionary<(int, int), List> _groundCardSpatialHash = new Dictionary<(int, int), List>(); private readonly Dictionary> _groundCardRecordsByTile = new Dictionary>(); private long _currentGroundCardOwnerTileKey = long.MinValue; private const float PrimaryCoverageCellSize = 16f; private readonly Dictionary<(int, int), List> _primaryCoverageSpatialHash = new Dictionary<(int, int), List>(); private readonly Stack _forestChunkBufferPool = new Stack(64); private readonly Queue _coverageSectorLightweightQueue = new Queue(); private readonly HashSet _coverageSectorKnownKeys = new HashSet(); private readonly List _activeCoverageAuditJobs = new List(2); private readonly long[] _activeCoverageSectorsByRing = new long[5]; private readonly long[] _coverageAuditedCellsByRing = new long[5]; private readonly long[] _coverageUncoveredCellsByRing = new long[5]; private readonly long[] _coverageRemainingCellsByRing = new long[5]; private long _coverageAuditJobsRetained; private long _coverageAuditJobsCancelled; private long _coverageAuditJobsUnexpectedlyRestarted; private long _coverageUnresolvedGapCells; private long _coveragePooledBufferAllocations; private long _coverageRepairCardsAccepted; private long _coverageCoastalRecoveriesAccepted; private readonly long[] _coverageSectorsCompletedByRing = new long[5]; private long _coverageCellsIncorrectlySatisfiedByDistantCard; private readonly List _coverageRepairQueue = new List(); private readonly HashSet _coverageRepairQueuedKeys = new HashSet(); private readonly Dictionary _coverageRepairMeshBuffers = new Dictionary(); private readonly Stack _coverageRepairMeshBufferPool = new Stack(16); private readonly List _coverageRepairScratchVertices = new List(16); private readonly List _coverageRepairScratchUvs = new List(16); private readonly List _coverageRepairScratchTriangles = new List(24); private long _coverageRepairTileCounter; private long _groundCardsConsidered; private long _groundCardsAccepted; private long _groundCardsRejectedFloatingOrBurial; private long _groundCardsRejectedFloating; private long _groundCardsRejectedBurial; private long _groundCardsRejectedOpenWater; private long _groundCardsRejectedUnsupportedRoot; private StrictFinalRejectReason _lastStrictFinalRejectReason; private long _groundCardsRejectedHeightVariance; private long _groundCardsDuplicatesSuppressed; private long _plainsDuplicatesSuppressed; private long _plainsCardsRejectedGroundError; private float _plainsMaxFinalGroundError; private long _plainsStackedCardViolations; private string _lastStackedCardViolation = "none"; private float _maxBaseHeightDisagreement; private float _maxFinalWorldHeightmapError; private bool _groundTransformOk = true; private string _groundTransformDetail = "no comparison yet"; private long _renderedGroundSourceFarMeshCount; private long _renderedGroundSourceProviderFallbackCount; private long _renderedGroundSourceNativeCount; private string _lastGroundedRenderedSource = "none"; private float _lastRenderedGroundY; private float _lastFinalVisibleRootY; private float _lastFinalVisibleRootError; private float _lastAppliedVerticalAdjustment; private float _maxFinalVisibleRootErrorObserved; private long _cardsCorrectedDownward; private long _cardsRejectedAfterVerticalCorrection; private long _slopeAwareCardsTested; private long _slopeAwareEdgeFloatingDetected; private long _slopeAwareWidthReduced; private long _slopeAwareSplitAccepted; private long _slopeAwareRejectedAfterSplit; private float _slopeAwareMaxFinalEdgeError; private double _mountainHeightSampleSum; private double _mountainWidthSampleSum; private long _mountainSizeSampleCount; private long _mountainProportionallyReduced; private long _mountainSplitOnSlopes; private long _standardWidthCapHits; private long _mountainStandardWidthCapHits; private long _blackForestStandardWidthCapHits; private long _biomeWidthCapHits; private float _pendingMountainRequestedVisibleWidth; private bool _pendingMountainWidthCapApplied; private bool _pendingMountainGenericCapApplied; private string _mountainCardDimensionSample = "not sampled"; private bool _mountainCardDimensionsLogged; private readonly float[] _ringLargestObservedCoverageGap = new float[5]; private readonly long[] _ringCoverageFallbackAccepted = new long[5]; private readonly long[] _ringCoverageFallbackAttempted = new long[5]; private readonly long[] _ringCoverageFallbackFailed = new long[5]; private readonly long[] _ringCoverageSlopeRejections = new long[5]; private readonly long[] _ringCoverageWaterRejections = new long[5]; private readonly long[] _ringCoverageGroundingRejections = new long[5]; private long _blackForestCoverageFallbackAccepted; private long _blackForestCoverageSecondPassAccepted; private long _blackForestCrossedCardsEmitted; private long _blackForestSinglePlaneCardsDetected; private double _blackForestFinalWidthSum; private double _blackForestFinalHeightSum; private long _blackForestFinalCardSamples; private float _blackForestWorstFinalRatio = float.MaxValue; private long _blackForestProportionallyReduced; private long _blackForestSplitOnSlopes; private long _blackForestRejectedTooThin; private long _blackForestBroadCellSelections; private long _blackForestStandardCellSelections; private long _blackForestNarrowCellSelections; private readonly long[] _blackForestAtlasCellSelections = new long[4]; private readonly long[] _blackForestTallPineSelectionsByRing = new long[5]; private readonly long[] _blackForestSelectionsByRing = new long[5]; private int _blackForestTallPineAtlasIndex = -1; private long _blackForestAcceptedCardTotal; private long _blackForestAtlasSelectionRejected; private long _blackForestScaleFallbacks; private bool _blackForestCrossedPlaneSelfTestRun; private float _pendingBlackForestRequestedVisibleWidth; private bool _pendingBlackForestWidthCapApplied; private bool _pendingBlackForestGenericCapApplied; private string _blackForestPineDimensionSample = "not sampled"; private bool _blackForestPineDimensionsLogged; private long _farLodLogicalCards; private long _farLodCrossedCardsRendered; private long _farLodSinglePlaneCardsRendered; private long _farLodTrianglesAvoided; private double _farLodAlphaTestedAreaAvoided; private long _rendererChunksSplitByCardLimit; private long _rendererChunksSplitByTriangleLimit; private ViewFacingForestOverloadState _viewFacingForestOverloadState; private ViewFacingForestOverloadState _currentForestBuildGeometryState; private string _viewFacingForestThresholdState = "below soft"; private float _viewFacingForestRecoveryEligibleSince = -1f; private bool _viewFacingForestOverloadGuardSafetyValid = true; private long _viewFacingForestOverloadTransitions; private long _visibleDetailedLogicalCards; private long _visibleDetailedCrossedCards; private long _visibleDetailedSinglePlaneCards; private long _visibleDetailedTriangles; private long _visibleDetailedVertices; private int _visibleDetailedTreeRenderers; private readonly int[] _visibleTreeRenderersByRing = new int[5]; private bool _forceImmediateTreeMaterialRefresh; private float _treeMaterialUpdatesPerSecond; private long _treeMaterialRateLastPassCount; private float _treeMaterialRateLastSampleRealtime = -1f; private string _worstCoverageBiome = "none"; private ForestRing _worstCoverageRing; private float _worstCoverageGap; private string _worstCoverageRejectionCause = "none"; private readonly long[] _ringRepairJobsPending = new long[5]; private readonly long[] _ringRepairsAccepted = new long[5]; private readonly long[] _ringRepairRetriesExhausted = new long[5]; private readonly long[] _ringValidCellsScanned = new long[5]; private readonly long[] _ringCoveredCellsScanned = new long[5]; private bool _swampDiagnosticColourApplied; private long _finalBiomeResamples; private long _biomeChangedAfterRetry; private long _swampWrongBiomeRejections; private long _swampCandidatesRejectedNoValidGround; private long _groundCardsSplitOnUnevenTerrain; private bool _swampDiagnosticOriginalColourCaptured; private Color _swampDiagnosticOriginalColour = Color.white; private long _swampAccepted; private long _mountainCandidates; private long _mountainAccepted; private long _plainsCandidates; private long _plainsAccepted; private long _mixedCandidates; private float _traceNearestRawCandidateDistance = float.MaxValue; private float _traceNearestExclusionRejectedDistance = float.MaxValue; private float _traceNearestGroundingRejectedDistance = float.MaxValue; private float _traceNearestBiomeRejectedDistance = float.MaxValue; private float _traceNearestAcceptedCardDistance = float.MaxValue; private float _traceLastResetRealtime = -1f; private long _handoffFillBandCandidatesSeen; private long _handoffFillBandCandidatesForced; private long _handoffFillBandCandidatesFilled; private long _handoffFillBandGapViolations; private long _handoffFillBandCandidatesSkippedByChance; private float _handoffFillLargestObservedGap; private float _handoffFillLastRowAcceptedX = float.NaN; private float _handoffFillLastRowZ = float.NaN; private long _coastalLandRecoverySearches; private long _coastalLandRecoveryAccepted; private long _coastalFoliageOverhangPlacementsAccepted; private int _fullResolutionTerrainTilesBuilt; private Color _lastSharedTerrainMaterialColour = Color.white; private bool _terrainColourRingSourceLogged; private Color _terrainColourDiagnosticProvider = Color.white; private Color _terrainColourDiagnosticNear = Color.white; private Color _terrainColourDiagnosticFar = Color.white; private Color _terrainColourDiagnosticHorizon = Color.white; private float _terrainColourDiagnosticNearRatio = 1f; private float _terrainColourDiagnosticFarRatio = 1f; private float _terrainColourDiagnosticHorizonRatio = 1f; private bool _terrainColourPostCorrectionDarkening; private bool _terrainColourRadialMultiplierActive; private string _terrainColourProviderSpace = "unresolved"; private float _nextTerrainColourDiagnosticUpdate; private GameObject _root; private IWorldDataProvider _provider; private string _providerSelectionReason = "not initialized"; private string _providerFailure = ""; private string _duplicateDllStatus = "not scanned"; private string _legacyConfigStatus = "not scanned"; private string _renderLimitsStatus = "not checked"; private string _nativeEnvelopeDetails = "not computed"; private string _nativeTreeRangeSource = "not detected"; private string _hazeStatus = "disabled"; private string _weatherName = "unknown"; private string _weatherClassification = "unknown"; private string _externalFogStatus = "not checked"; private string _hazeYieldReason = "none"; private bool _renderLimitsUsable; private float _nativeEnvelopeRadius = 900f; private float _nativeTreeViewDistance = 215f; private bool _hazeApplied; private float _savedFogDensity; private float _targetFogDensity; private float _appliedFogDensity; private ClearSkyWeatherTier _clearSkyTier = ClearSkyWeatherTier.Bad; private string _clearSkyPreservationReason = "none"; private float _clearSkyCurrentBlend; private float _clearSkyTargetBlend; private string _clearSkyBiomeName = "unknown"; private float _clearSkyAppliedFogMultiplier = 1f; private float _clearSkyAppliedHazeMultiplier = 1f; private float _clearSkyAppliedTintMultiplier = 1f; private float _lastClearSkyEnvironmentChangeRealtime = -1f; private string _lastClearSkyException = "none"; private bool _clearSkyRestoreOk = true; private bool _playerBiomeApiChecked; private bool _playerBiomeApiAvailable; private bool _cloudRenderersScanned; private readonly List _cloudRenderers = new List(); private readonly Dictionary _cloudRendererOriginalColours = new Dictionary(); private readonly Dictionary _cloudRendererOriginalBlocks = new Dictionary(); private MaterialPropertyBlock _cloudPropertyBlock; private string _cloudControlStatus = "not scanned yet"; private float _cloudOriginalAlphaForDiagnostics = 1f; private float _cloudAppliedOpacityMultiplier = 1f; private bool _cloudRestoreOk = true; private bool _savedFogEnabled; private string _lastHazeEnvironmentKey = ""; private bool _fogColourDiagnosticApplied; private Color _savedFogColour = Color.white; private bool _fogColourDiagnosticOverwritten; private readonly Dictionary _nativeTerrainDiagnosticOriginalBlocks = new Dictionary(); private bool _nativeTerrainDiagnosticApplied; private string _nativeTerrainDiagnosticStatus = "not selected"; private TrueColourDiagnosticTarget _lastTrueColourDiagnosticTarget; private Camera _farClipCamera; private float _savedFarClip; private bool _farClipApplied; private string _lastWorldKey = ""; private float _nextProviderRetry; private float _nextVisibilityUpdate; private bool _rebuildRequested = true; private bool _hasBuildAnchor; private Vector3 _buildAnchor; private string _lastRebuildReason = "startup"; private QualityPreset? _lastAppliedQualityPreset; private float? _lastAppliedExtensionDistance; private float? _lastAppliedDensitySignature; private bool _pendingDensityInvalidation; private string _lastTrueColourTierKey; private float _pendingTerrainColourRebuildDebounce; private float _trueColourCurrentBlend; private float _trueColourTargetBlend; private bool _trueColourBlendInitialized; private float? _lastAppliedNativeTreelineHandoff; private float _pendingTreelineRebuildDebounce; private bool _calibrationModeActive; private float _calibrationRadius = 325f; private GameObject _calibrationGuideObject; private LineRenderer _calibrationGuideRenderer; private Material _calibrationGuideMaterial; private Material _calibrationMarkerMaterial; private Material _calibrationFacingMarkerMaterial; private Material _calibrationTestGuideMaterial; private float _lastCalibrationGuideRadius = -1f; private Vector3 _lastCalibrationGuideOrigin = new Vector3(float.NaN, float.NaN, float.NaN); private int _calibrationGuidePointCount; private readonly List _calibrationSamples = new List(); private bool _calibrationToggleKeyDetectedThisFrame; private float _calibrationGateWarningRemaining; private string _calibrationOriginMode = "n/a"; private string _calibrationGuideShaderName = "none"; private int _calibrationValidSamples; private int _calibrationFailedSamples; private float _calibrationMinSampledHeight = float.NaN; private float _calibrationMaxSampledHeight = float.NaN; private float _lastCalibrationGuideRebuildRealtime = -1f; private string _lastCalibrationException = "none"; private readonly List _calibrationMarkerRenderers = new List(); private GameObject _calibrationMarkerRoot; private LineRenderer _calibrationFacingMarkerRenderer; private GameObject _calibrationTestGuideObject; private LineRenderer _calibrationTestGuideRenderer; private float _lastCalibrationTestGuideRadius = -1f; private Vector3 _lastCalibrationTestGuideOrigin = new Vector3(float.NaN, float.NaN, float.NaN); private string _status = "Waiting for world."; private readonly Dictionary _terrainTiles = new Dictionary(); private readonly Dictionary _forestTiles = new Dictionary(); private readonly Queue _terrainQueue = new Queue(); private readonly HashSet _terrainQueuedKeys = new HashSet(); private readonly List _forestAddQueue = new List(); private readonly Dictionary _forestAddJobsByKey = new Dictionary(); private readonly Dictionary _forestTileCache = new Dictionary(); private readonly Queue _forestRetirementQueue = new Queue(); private int _forestGenerationEpoch; private Vector3 _streamingCameraForwardFlat = Vector3.forward; private Vector3 _streamingViewOrigin; private string _lastIncrementalUpdateReason = "startup"; private bool _forestPausedPreviousFrame; private int _forestDesiredChunkCount; private int _forestRetainedUnchangedCount; private int _forestQueuedAddCount; private int _forestQueuedRemoveCount; private int _forestChunksBuiltThisFrame; private int _forestMeshesUploadedThisFrame; private int _forestChunksRetiredThisFrame; private float _forestGenerationTimeThisFrameMs; private float _forestMeshUploadTimeThisFrameMs; private float _forestRetirementTimeThisFrameMs; private double _forestChunkBuildMsSum; private long _forestChunkBuildSampleCount; private float _forestLongestChunkBuildMs; private string _forestLastMajorHitch = "none"; private int _forestCacheHits; private int _forestCacheMisses; private int _forestCacheEvictions; private int _forestCancelledObsoleteJobs; private int _forestFailedJobsPermanent; private bool _forestDeterministicRestoreOk = true; private string _forestDeterministicRestoreDetail = "no comparison yet"; private readonly Dictionary _forestTileLastKnownHash = new Dictionary(); private readonly Dictionary _forestTileDeterminismRecords = new Dictionary(); private readonly HashSet _determinismWarningsThisEpoch = new HashSet(); private long _determinismComparisonsSkippedSignature; private long _determinismComparisonsSkippedPartial; private long _determinismWarningsSuppressed; private bool _deterministicSelfTestRun; private bool _forestAtlasBarrierActive; private bool _forestAtlasBarrierEverActive; private float _adaptiveAverageFrameMs = 16.67f; private float _adaptivePressure; private float _adaptiveStableSeconds; private float _adaptiveHardSpikeCooldownRemaining; private float _adaptiveBuildOverrunCooldownRemaining; private float _adaptiveEffectiveGenerationBudgetMs = 2f; private int _adaptiveEffectiveMeshUploads = 2; private int _adaptiveEffectiveChunkActivations = 8; private int _adaptiveEffectiveTilesPerFrame = 1; private string _adaptiveGovernorState = "initializing"; private int _forestCacheActivationsThisFrame; private int _forestCacheActivationsDeferredThisFrame; private int _reinforcementJobsDeferredThisFrame; private Vector3 _lastStreamingOriginForVelocity; private Vector3 _streamingVelocityFlat; private bool _hasStreamingVelocitySample; private int _adaptiveTerrainCadenceCounter; private int _terrainBuildFramesDeferredForPerformance; private float _lastPrimaryProgressRealtime; private float _lastReinforcementProgressRealtime; private float _lastCoverageProgressRealtime; private float _lastCoverageSectorProgressRealtime; private long _primaryStarvationProgressSteps; private long _reinforcementStarvationProgressSteps; private long _coverageStarvationProgressSteps; private bool _forestBootstrapActiveLastFrame; private long _forestCompletedTilesTotal; private long _forestCancelledJobsTotal; private long _forestDeferredUploadsTotal; private float _forestAtlasReadyRealtime = -1f; private int _startupForestBuildFrameCounter; private int _startupTerrainBuildFrameCounter; private long _startupForestFramesDeferred; private long _startupTerrainFramesDeferred; private long _startupCoverageRepairFramesDeferred; private bool _expensiveStartupSelfTestSkipLogged; private int _forestActiveResumableJobs; private string _forestCurrentJobStage = "idle"; private int _forestCandidatesProcessedThisFrame; private int _forestGroundingSamplesThisFrame; private int _forestMeshVerticesThisFrame; private float _forestLongestResumableStepMs; private long _forestCandidateCapHitCount; private int _forestCurrentJobCandidateIndex; private int _forestCurrentJobCandidateTotal; private long _forestTilesCompletedFullCandidateSet; private long _forestCompletedCandidateEvaluations; private int _forestPartiallyProcessedResumableTiles; private long _forestJobsRestartedUnexpectedly; private float _forestLongestCandidateBatchMs; private float _forestLongestMeshBatchMs; private float _forestLongestGroundingSliceMs; private float _forestLongestMeshUploadMs; private int _forestTerrainSamplesThisFrame; private int _forestFootprintChecksThisFrame; private int _forestSlopeChecksThisFrame; private int _forestMeshCardsAppendedThisFrame; private int _forestChunkActivationsThisFrame; private int _forestCompletedTileCommitsThisFrame; private int _forestPressureSlowFrameStreak; private bool _forestGenerationPressureMode; private float _forestGenerationPressureRecoveryRemaining; private float _forestCurrentCpuBudgetMs = 1f; private Stopwatch _forestFrameBudgetStopwatch; private Vector3 _lastPressureCameraForward = Vector3.forward; private float _forestCameraAngularSpeed; private bool _forestTeleportPressureThisFrame; private bool _forestFrameTimePressure; private long _forestCancelledGenerationJobs; private long _forestPooledBufferAllocations; private long _forestGcBytesAtSecondStart; private long _forestGcAllocationsThisSecond; private float _forestGcSecondStartedRealtime; private float _lastForestJobWarningRealtime = -10f; private float _lastBudgetAccountingWarningRealtime = -10f; private float _lastGroundTransformWarningRealtime = -10f; private long _densityRequestedCards; private long _densityAcceptedCards; private long _densityRejectedCards; private long _baselinePrimaryCardsAccepted; private long _reinforcementCardsAccepted; private long _cardsBlockedByPerTileCap; private long _cardsBlockedByGlobalBudget; private long _cardsBlockedByCandidateCompletion; private long _cardsBlockedByClusterCap; private long _cardsBlockedByPlaneCap; private long _cardsBlockedByRingReservation; private long _cardsBlockedByReinforcementCap; private long _cardsBlockedByOptionalDefer; private long _cardsBlockedByBootstrapSafety; private long _cardsBlockedByMeshLimit; private long _blackForestDensityCardsAccepted; private long _meadowsDensityCardsAccepted; private long _swampDensityCardsAccepted; private long _mountainDensityCardsAccepted; private long _plainsDensityCardsAccepted; private bool _treeDensityPresetInitialized; private TreeCardDensityPreset? _lastAppliedTreeCardDensityPreset; private bool _manualTreeCardValuesPreserved; private ForestBuildContinuation _activeForestBuild; private int _forestRetainedActiveLastSync; private int _forestRetainedPendingLastSync; private int _forestRetainedCachedLastSync; private long _forestDuplicateJobsDetected; private long _forestCurrentlyBuildingTileKey = long.MinValue; private float _lastMovementSyncRealtime = -1000f; private Material _sharedTerrainMaterial; private Material _forestMaterial; private Material _treeCardMaterial; private Material _canopyCardMaterial; private Material _mountainBiomeCardMaterial; private Material _swampBiomeCardMaterial; private Texture2D _treeAtlasTexture; private Texture2D _canopyAtlasTexture; private Texture2D _mountainBiomeAtlasTexture; private Texture2D _swampBiomeAtlasTexture; private readonly float[] _treeAtlasVisibleRootBottomTrim = new float[4]; private readonly float[] _canopyAtlasVisibleRootBottomTrim = new float[4]; private readonly float[] _mountainAtlasVisibleRootBottomTrim = new float[4]; private readonly float[] _swampAtlasVisibleRootBottomTrim = new float[4]; private readonly AtlasVisibleBounds[] _treeAtlasVisibleBounds = new AtlasVisibleBounds[4]; private readonly AtlasVisibleBounds[] _canopyAtlasVisibleBounds = new AtlasVisibleBounds[4]; private readonly AtlasVisibleBounds[] _mountainAtlasVisibleBounds = new AtlasVisibleBounds[4]; private readonly AtlasVisibleBounds[] _swampAtlasVisibleBounds = new AtlasVisibleBounds[4]; private readonly float[] _mountainAtlasVisibleWidthFraction = new float[4] { 1f, 1f, 1f, 1f }; private readonly float[] _treeAtlasVisibleWidthFraction = new float[4] { 1f, 1f, 1f, 1f }; private string _treeAtlasStatus = "disabled"; private string _treeAtlasShader = "none"; private string _canopyAtlasStatus = "disabled"; private string _canopyAtlasShader = "none"; private string _mountainBiomeAtlasStatus = "disabled"; private string _mountainBiomeAtlasShader = "none"; private string _swampBiomeAtlasStatus = "disabled"; private string _swampBiomeAtlasShader = "none"; private string _lastAtlasMaterialError = "none"; private float _nextAtlasMaterialRetry; private bool _forestAtlasTextureWaitLogged; private bool _forestAtlasMaterialsReadyLogged; private bool _treeCardCutoutMaterialValid; private bool _treeCardCutoutMaterialValidLogged; private string _treeCardCutoutMaterialDetail = "not created"; private int _treeAtlasMipCount; private int _canopyAtlasMipCount; private int _mountainAtlasMipCount; private int _swampAtlasMipCount; private double _atlasOriginalQuadAreaSum; private double _atlasTightenedQuadAreaSum; private long _atlasTightenedPlaneSamples; private readonly double[] _atlasOriginalAreaByCell = new double[4]; private readonly double[] _atlasTightenedAreaByCell = new double[4]; private readonly long[] _atlasAreaSamplesByCell = new long[4]; private long _postMeshValidationAttempts; private long _postMeshValidatedMeshes; private long _postMeshTrueViolations; private float _postMeshWorstVisibleRootError; private string _postMeshWorstViolation = "none"; private int _currentTilePostMeshViolationCount; private float _currentTilePostMeshWorstError; private string _currentTilePostMeshWorstDetail = "none"; private float _lastPostMeshWarningRealtime = -1000f; private long _postMeshRootFloatCorrections; private double _postMeshRootFloatCorrectionMetres; private int _postMeshDiagnosticEpoch = -1; private bool _postMeshValidatorInitializedLogged; private bool _postMeshEpochCompletionLogged; private long _postMeshEpochUnresolvedViolations; private long _postMeshEpochMeshesChecked; private readonly HashSet _postMeshTileSummariesThisEpoch = new HashSet(); private GUIStyle _overlayStyle; private GUIStyle _calibrationBannerStyle; private int _lastBuiltForestClusters; private int _lastBuiltTreeCards; private int _lastBuiltCanopyCards; private float _nearestForestDensity; private Vector3 _nearestForestTileCenter; private float _nearestForestTileDistance; private int _forestChunkCount; private int _forestNearCulledChunkCount; private float _nearestEnabledForestChunkEdge; private bool _forestHandoffOk; private int _visibleCardQuadsHandoffTo100; private int _visibleCardQuadsHandoff100To350; private int _lastTerrainBudget; private int _lastForestBudget; private int _lastTerrainTileRequests; private int _lastTerrainTileQueued; private int _lastForestTileRequests; private int _lastForestTileQueued; private string _lastQueueBudgetStatus = "not queued"; private Vector2 _lastMapUv; private float _lastAnchorForestDensity; private string _lastMapAlignmentStatus = "not sampled"; private Vector3 _nearestTerrainTileCenter; private float _nearestTerrainTileDistance = float.MaxValue; private Vector3 _farthestTerrainTileCenter; private float _farthestTerrainTileDistance = -1f; private string _lastTerrainTintNearestStatus = "not sampled"; private string _lastTerrainTintFarthestStatus = "not sampled"; private int _remainingTreeCardPlaneBudget; private int _remainingCanopyPlaneBudget; private int _activeTreePlanesReported; private int _activeCanopyPlanesReported; private int _forestPlanesAddedThisUpdate; private int _forestPlanesRemovedThisUpdate; private int _maxBudgetAccountingDriftObserved; private int _budgetReconciliationCorrections; private RingPlaneCounts[] _ringPlaneCountsCache; private ForestRing _lastBuiltTileRing; private ForestRing _currentBudgetStarvationRing; private bool _currentBudgetStarvationDetected; private readonly int[] _ringValidLandSectors = new int[5]; private readonly int[] _ringCoveredSectors = new int[5]; private readonly int[] _ringEmptyValidSectors = new int[5]; private readonly int[] _ringPendingPrimaryJobs = new int[5]; private readonly bool[,] _ringSectorHasValidLand = new bool[5, 16]; private readonly HashSet _primaryCoverageKeys = new HashSet(); private bool _buildingPrimaryCoverageJob; private bool _buildingReinforcementJob; private bool _presetContractValid; private string _presetContractFailureDetail = "not run"; private bool _forestMeshValidationOk = true; private string _forestMeshValidationViolationDetail = "none"; private long _forestMeshesValidated; private long _forestMeshesRejectedInvalid; private long _atlasMeshZeroLengthNormals; private float _atlasMeshMinimumNormalMagnitude = 1f; private int[] _ringBuiltChunkCounts = new int[5]; private int[] _ringVisibleChunkCounts = new int[5]; private float[] _ringMinVisibleDistance = new float[5] { float.MaxValue, float.MaxValue, float.MaxValue, float.MaxValue, float.MaxValue }; private float[] _ringMaxVisibleDistance = new float[5] { -1f, -1f, -1f, -1f, -1f }; private long _groundGateRejectedCards; private long _groundGateRejectedWater; private long _groundGateRejectedUnsupported; private long _groundGateRejectedHeightMismatch; private long _groundGateRejectedProxy; private const float BlackForestBroadCellFractionThreshold = 0.55f; private const float BlackForestStandardCellFractionThreshold = 0.35f; private bool _goldenHighProfileLogged; private bool _movementRetentionSelfTestRun; private static readonly string[] RingNames = new string[5] { "Handoff", "Near", "Mid", "Far", "Horizon" }; private static int _lastMotionPropsZeroed; private static PresetRuntimeProfile CreatePresetRuntimeProfile(QualityPreset preset, string name, float extensionDistance, bool useWorldMaximum, int maximumForestTiles, int treeBudget, int canopyBudget, int panicTileCeiling, int tilesBuiltPerFrame, int maximumMeshUploadsPerFrame) { return new PresetRuntimeProfile { Preset = preset, Name = name, ExtensionDistance = extensionDistance, UseWorldMaximum = useWorldMaximum, MaximumForestTiles = maximumForestTiles, GlobalTreeCardPlaneBudget = treeBudget, GlobalCanopyPlaneBudget = canopyBudget, PanicTileCeiling = panicTileCeiling, TilesBuiltPerFrame = tilesBuiltPerFrame, MaximumMeshUploadsPerFrame = maximumMeshUploadsPerFrame }; } private void Awake() { BindConfig(); RunPresetContractValidation(); if (!_presetContractValid) { ((BaseUnityPlugin)this).Logger.LogError((object)("PRESET CONTRACT VIOLATION -- release-blocking startup failure: " + _presetContractFailureDetail)); ((Behaviour)this).enabled = false; return; } if (!RunGoldenCandidateCompletionSelfTest()) { ((BaseUnityPlugin)this).Logger.LogError((object)"GOLDEN 900-CANDIDATE COMPLETION SELF-TEST FAILED"); ((Behaviour)this).enabled = false; return; } if (!RunGoldenRenderingInvariantSelfTest()) { ((BaseUnityPlugin)this).Logger.LogError((object)"GOLDEN RENDERING INVARIANT SELF-TEST FAILED"); ((Behaviour)this).enabled = false; return; } if (!ValidateGoldenForestPerformanceSafetyContract()) { ((BaseUnityPlugin)this).Logger.LogError((object)"GOLDEN FOREST CONTENT SAFETY CONTRACT FAILED"); ((Behaviour)this).enabled = false; return; } ValidateGoldenHighTreeCardProfile(); ScanDuplicateDlls(); ReportIgnoredLegacySettings(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"New Horizons Treelines v4.6.31 Swamp Trees Default Off loaded. Build ID NHT-4.6.31-20260717-SWAMP-TREES-DEFAULT-OFF."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"World Data Mode is Auto by default: Better Continents custom maps are preserved when available; native procedural worlds use the ProceduralWorld provider."); RequestFullReload("startup"); } private bool RunGoldenCandidateCompletionSelfTest() { int num = 1521; int num2 = 900; int num3 = 0; int num4 = 0; int num5 = 0; for (int i = 0; i < num; i++) { long num6 = (long)i * (long)num2 / num; long num7 = (long)(i + 1) * (long)num2 / num; if (num7 != num6) { if (num4 >= 48) { num5++; num4 = 0; } num3++; num4++; } } bool flag = num3 == 900 && num5 == 18 && num4 == 36; if (flag) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"GOLDEN 900-CANDIDATE COMPLETION SELF-TEST PASSED"); } return flag; } private bool RunGoldenRenderingInvariantSelfTest() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_006c: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List uvs = new List(); List list2 = new List(); Vector2 zero = Vector2.zero; Vector2 up = Vector2.up; Vector2 one = Vector2.one; Vector2 right = Vector2.right; AddAtlasCutoutQuad(list, uvs, list2, Vector3.zero, Vector3.up, Vector3.one, Vector3.right, zero, up, one, right); AddAtlasCutoutQuad(list, uvs, list2, Vector3.zero, Vector3.forward, Vector3.one, Vector3.right, zero, up, one, right); int num = HashCombine(37199, 17, 29); int num2 = HashCombine(37199, 17, 29); int num3 = StableForestCardRecord(num, 123.25f, -67.75f, 0, (Biome)8); int num4 = StableForestCardRecord(num2, 123.25f, -67.75f, 0, (Biome)8); bool flag = GoldenHighDensityProfile.CandidateTotal == 900 && NearlyEqual(GoldenHighDensityProfile.DensityMultiplier, 13.036f) && GoldenHighDensityProfile.MaximumClusters == 6799 && GoldenHighDensityProfile.MaximumTreePlanes == 10945 && NearlyEqual(GoldenHighDensityProfile.GlobalDistributedDensity, 1.65f) && NearlyEqual(GoldenHighDensityProfile.BlackForestDistributedDensity, 2f) && NearlyEqual(GoldenHighDensityProfile.MeadowsDistributedDensity, 1.3f) && NearlyEqual(GoldenHighDensityProfile.MountainDistributedDensity, 1.15f) && NearlyEqual(GoldenHighDensityProfile.PlainsDistributedDensity, 0.25f) && NearlyEqual(1.55f, 1.55f) && NearlyEqual(2f, 2f) && NearlyEqual(0.42f, 0.42f) && NearlyEqual(0.72f, 0.72f) && NearlyEqual(18f, 18f) && NearlyEqual(1.35f, 1.35f) && NearlyEqual(1.2f, 1.2f) && NearlyEqual(0.9f, 0.9f) && NearlyEqual(1.3f, 1.3f) && NearlyEqual(0.45f, 0.45f) && NearlyEqual(0.78f, 0.78f) && NearlyEqual(22f, 22f) && MaxCanopyPlanesPerTile() == 9906 && NearlyEqual(BlackForestTallPineTarget(ForestRing.Handoff), 0.65f) && NearlyEqual(BlackForestTallPineTarget(ForestRing.Near), 0.7f) && NearlyEqual(BlackForestTallPineTarget(ForestRing.Mid), 0.78f) && NearlyEqual(BlackForestTallPineTarget(ForestRing.Far), 0.85f) && NearlyEqual(BlackForestTallPineTarget(ForestRing.Horizon), 0.85f) && num == num2 && num3 == num4 && num3 == 1391525808 && list.Count == 8 && list2.Count == 12; if (flag) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"GOLDEN RENDERING INVARIANT SELF-TEST PASSED"); } return flag; } private bool ValidateGoldenForestPerformanceSafetyContract() { string a = PerformanceSafetyContentFingerprint(); ViewFacingForestOverloadState viewFacingForestOverloadState = _viewFacingForestOverloadState; _viewFacingForestOverloadState = ViewFacingForestOverloadState.Hard; _viewFacingForestOverloadState = viewFacingForestOverloadState; string b = PerformanceSafetyContentFingerprint(); bool flag = (_viewFacingForestOverloadGuardSafetyValid = string.Equals(a, b, StringComparison.Ordinal) && GoldenHighDensityProfile.CandidateTotal == 900 && GoldenHighDensityProfile.MaximumClusters == 6799 && GoldenHighDensityProfile.MaximumTreePlanes == 10945); if (flag) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"GOLDEN FOREST CONTENT PRESERVED"); } return flag; } private void MigrateLegacyPresetNameOnce() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; if (string.IsNullOrEmpty(configFilePath) || !File.Exists(configFilePath)) { return; } string[] array = File.ReadAllLines(configFilePath); bool flag = false; string text = null; for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.StartsWith("[", StringComparison.Ordinal) && text2.EndsWith("]", StringComparison.Ordinal)) { flag = string.Equals(text2, "[General]", StringComparison.OrdinalIgnoreCase); } else if (flag && !text2.StartsWith("#", StringComparison.Ordinal)) { int num = text2.IndexOf('='); if (num > 0 && string.Equals(text2.Substring(0, num).Trim(), "Quality Preset", StringComparison.OrdinalIgnoreCase)) { text = text2.Substring(num + 1).Trim(); break; } } } QualityPreset value; if (string.Equals(text, "Performance", StringComparison.OrdinalIgnoreCase)) { value = QualityPreset.VeryLow; } else if (string.Equals(text, "Extreme", StringComparison.OrdinalIgnoreCase)) { value = QualityPreset.Horizon; } else { if (!string.Equals(text, "Cinematic", StringComparison.OrdinalIgnoreCase)) { return; } value = QualityPreset.Ultra; } _qualityPreset.Value = value; ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Migrated legacy Quality Preset '" + text + "' to '" + value.ToString() + "'.")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Legacy preset migration could not inspect the CFG: " + ex.GetType().Name + ": " + ex.Message)); } } private void RunPresetContractValidation() { _presetContractValid = true; _presetContractFailureDetail = "none"; string[] array = new string[10] { "Preset", "Name", "ExtensionDistance", "UseWorldMaximum", "MaximumForestTiles", "GlobalTreeCardPlaneBudget", "GlobalCanopyPlaneBudget", "PanicTileCeiling", "TilesBuiltPerFrame", "MaximumMeshUploadsPerFrame" }; FieldInfo[] fields = typeof(PresetRuntimeProfile).GetFields(BindingFlags.Instance | BindingFlags.Public); for (int i = 0; i < fields.Length; i++) { bool flag = false; for (int j = 0; j < array.Length; j++) { if (fields[i].Name == array[j]) { flag = true; break; } } if (!flag) { PresetContractViolation("schema", "only the ten workload fields", fields[i].Name, "PresetRuntimeProfile"); } } if (fields.Length != array.Length) { PresetContractViolation("schema", array.Length.ToString(CultureInfo.InvariantCulture) + " fields", fields.Length.ToString(CultureInfo.InvariantCulture), "PresetRuntimeProfile"); } QualityPreset[] array2 = new QualityPreset[7] { QualityPreset.VeryLow, QualityPreset.Low, QualityPreset.Balanced, QualityPreset.Medium, QualityPreset.High, QualityPreset.Ultra, QualityPreset.Horizon }; float[] array3 = new float[7] { 500f, 1000f, 2000f, 4000f, 7000f, 10000f, 0f }; int[] array4 = new int[7] { 220, 320, 500, 800, 1400, 2600, 2800 }; int[] array5 = new int[7] { 50000, 70000, 100000, 140000, 190000, 260000, 340000 }; int[] array6 = new int[7] { 35000, 50000, 75000, 105000, 145000, 195000, 255000 }; int[] array7 = new int[7] { 700, 950, 1400, 2100, 3000, 4000, 5000 }; int[] array8 = new int[7] { 2, 2, 3, 4, 5, 6, 7 }; int[] array9 = new int[7] { 2, 2, 3, 3, 4, 5, 6 }; PresetDefaultCheck("Native Treeline Calibrated Radius", 215f, _nativeTreelineCalibratedRadius); PresetDefaultCheck("Native Treeline Seam Overlap", 16f, _nativeTreelineSeamOverlap); PresetDefaultCheck("Canopy Handoff Offset", 1300f, _canopyHandoffOffset); PresetDefaultCheck("Handoff Fill Band Width", 450f, _handoffFillBandWidth); PresetDefaultCheck("Handoff Fill Candidate Spacing", 10f, _handoffFillCandidateSpacing); PresetDefaultCheck("Handoff Fill Maximum Valid-Land Gap", 16f, _handoffFillMaximumGap); PresetDefaultCheck("Handoff Fill Minimum Coverage", 0.95f, _handoffFillMinimumCoverage); PresetDefaultCheck("Enable Continuous Forest Coverage", expected: true, _enableContinuousForestCoverage); PresetDefaultCheck("Meadows Continuous Coverage", 1f, _continuousMeadowsCoverage); PresetDefaultCheck("Black Forest Continuous Coverage", 1f, _continuousBlackForestCoverage); PresetDefaultCheck("Swamp Continuous Coverage", 0.9f, _continuousSwampCoverage); PresetDefaultCheck("Mountain Continuous Coverage", 0.9f, _continuousMountainCoverage); PresetDefaultCheck("Plains Continuous Coverage", 0.2f, _continuousPlainsCoverage); PresetDefaultCheck("Mistlands Continuous Coverage", 0.7f, _continuousMistlandsCoverage); PresetDefaultCheck("Ashlands Continuous Coverage", 0.18f, _continuousAshlandsCoverage); PresetDefaultCheck("Deep North Continuous Coverage", 0.5f, _continuousDeepNorthCoverage); PresetDefaultCheck("Near Grid Retention", 1f, _continuousNearGridRetention); PresetDefaultCheck("Mid Grid Retention", 1f, _continuousMidGridRetention); PresetDefaultCheck("Far Grid Retention", 0.85f, _continuousFarGridRetention); PresetDefaultCheck("Horizon Grid Retention", 0.7f, _continuousHorizonGridRetention); PresetDefaultCheck("Enable Coastal Land Recovery", expected: true, _enableCoastalLandRecovery); PresetDefaultCheck("Coastal Land Recovery Radius", 48f, _coastalLandRecoveryRadius); PresetDefaultCheck("Coastal Land Recovery Attempts", 36, _coastalLandRecoveryAttempts); PresetDefaultCheck("Black Forest Near Minimum Subclusters", 5, _blackForestNearMinimumSubclusters); PresetDefaultCheck("Meadows Near Minimum Subclusters", 2, _meadowsNearMinimumSubclusters); PresetDefaultCheck("Allow Detailed Tree Foliage Overhang At Coast", expected: true, _allowDetailedTreeFoliageOverhangAtCoast); PresetDefaultCheck("Coastal Detailed Tree Water Safety Width", 3.5f, _coastalDetailedTreeWaterSafetyWidth); PresetDefaultCheck("Coastal Detailed Tree Near Water Reject Radius", 2.5f, _coastalDetailedTreeNearWaterRejectRadius); PresetDefaultCheck("Coastal Detailed Tree Minimum Above Water", 0.2f, _coastalDetailedTreeMinimumAboveWater); PresetDefaultCheck("Cluster Cell Size", 18f, _clusterCellSize); PresetDefaultCheck("Forest Density Multiplier", 13.036f, _forestDensityMultiplier); PresetDefaultCheck("Forest Density Threshold", 0f, _forestDensityThreshold); PresetDefaultCheck("Mixed Candidate Density Floor", 0.25f, _mixedCandidateDensityFloor); PresetDefaultCheck("Swamp Candidate Density Floor", 0.3f, _swampCandidateDensityFloor); PresetDefaultCheck("Mountain Candidate Density Floor", 0.24f, _mountainCandidateDensityFloor); PresetDefaultCheck("Plains Candidate Density Floor", 0.04f, _plainsCandidateDensityFloor); PresetDefaultCheck("Maximum Clusters Per Tile", 6799, _maximumClustersPerTile); PresetDefaultCheck("Maximum Tree Card Planes Per Tile", 10945, _maxTreeCardPlanesPerTile); PresetDefaultCheck("Maximum Candidate Cells Per Tile Build", 900, _maximumCandidateCellsPerTileBuild); PresetDefaultCheck("Candidate Evaluations Per Resumable Step", 48, _candidateEvaluationsPerResumableStep); PresetDefaultCheck("Hard Reject Slope", 52.366f, _hardSlopeRejectionThreshold); PresetDefaultCheck("Global Distributed Tree Density", 1.65f, _globalDistributedTreeDensity); PresetDefaultCheck("Black Forest Distributed Density", 2f, _blackForestDistributedDensity); PresetDefaultCheck("Meadows Distributed Density", 1.3f, _meadowsDistributedDensity); PresetDefaultCheck("Mountain Distributed Density", 1.15f, _mountainDistributedDensity); PresetDefaultCheck("Plains Distributed Density", 0.25f, _plainsDistributedDensity); PresetDefaultCheck("Maximum Canopy Planes Per Tile", 9906, _maxCanopyPlanesPerTile); PresetDefaultCheck("Native Treeline Boundary Chunk Size", 16f, _nativeTreelineBoundaryChunkSize); PresetDefaultCheck("Normal Forest Chunk Size", 64f, _normalForestChunkSize); PresetDefaultCheck("Near Cull Hysteresis", 4f, _nearCullHysteresis); PresetDefaultCheck("Native Treeline Seam Tolerance", 6f, _nativeTreelineSeamTolerance); PresetDefaultCheck("Meadows Distant Tree Density", 1.1f, _meadowsDistantTreeDensity); PresetDefaultCheck("Black Forest Distant Tree Density", 1.4f, _blackForestDistantTreeDensity); PresetDefaultCheck("Swamp Distant Tree Density", 1.2f, _swampDistantTreeDensity); PresetDefaultCheck("Mountain Distant Tree Density", 0.65f, _mountainDistantTreeDensity); PresetDefaultCheck("Plains Distant Tree Density", 0.25f, _plainsDistantTreeDensity); PresetDefaultCheck("Mistlands Distant Tree Density", 0.55f, _mistlandsDistantTreeDensity); PresetDefaultCheck("Ashlands Distant Tree Density", 0.2f, _ashlandsDistantTreeDensity); PresetDefaultCheck("Deep North Distant Tree Density", 0.35f, _deepNorthDistantTreeDensity); PresetDefaultCheck("Meadows Distant Canopy Density", 1f, _meadowsDistantCanopyDensity); PresetDefaultCheck("Black Forest Distant Canopy Density", 1.35f, _blackForestDistantCanopyDensity); PresetDefaultCheck("Swamp Distant Canopy Density", 1.05f, _swampDistantCanopyDensity); PresetDefaultCheck("Mountain Distant Canopy Density", 0.45f, _mountainDistantCanopyDensity); PresetDefaultCheck("Plains Distant Canopy Density", 0.1f, _plainsDistantCanopyDensity); PresetDefaultCheck("Mistlands Distant Canopy Density", 0.4f, _mistlandsDistantCanopyDensity); PresetDefaultCheck("Enable Strict Final Heightmap Validation", expected: true, _enableStrictFinalHeightmapValidation); PresetDefaultCheck("Final Root Embed Depth", 0.1f, _finalRootEmbedDepth); PresetDefaultCheck("Maximum Final Floating Error", 0.2f, _maxFinalGroundFloatingError); PresetDefaultCheck("Maximum Final Burial Error", 0.6f, _maxFinalGroundBurialError); PresetDefaultCheck("Maximum Standard Card Terrain Variance", 1.5f, _maxGroundHeightVarianceStandardCard); PresetDefaultCheck("Maximum Large Card Terrain Variance", 0.75f, _maxGroundHeightVarianceLargeCard); PresetDefaultCheck("Minimum Root Support Ratio", 0.8f, _minimumRootSupportRatio); PresetDefaultCheck("Minimum Footprint Support Ratio", 0.7f, _minimumFootprintSupportRatio); PresetDefaultCheck("Maximum Unsupported Span", 1.5f, _maximumUnsupportedSpan); PresetDefaultCheck("Maximum Standard Ground Card Width", 12f, _maximumStandardGroundCardWidth); PresetDefaultCheck("Maximum Swamp Ground Card Width", 10f, _maximumSwampGroundCardWidth); PresetDefaultCheck("Maximum Plains Ground Card Width", 10f, _maximumPlainsGroundCardWidth); PresetDefaultCheck("Maximum Proxy Ground Mass Width", 12f, _maximumProxyGroundMassWidth); PresetDefaultCheck("Reject Ground Cards Over Open Water", expected: true, _rejectGroundCardsOverOpenWater); PresetDefaultCheck("Split Large Cards On Uneven Terrain", expected: true, _splitLargeCardsOnUnevenTerrain); PresetDefaultCheck("Require Final Swamp Position Remains Swamp", expected: true, _requireFinalSwampPositionRemainsSwamp); PresetDefaultCheck("Minimum Swamp Biome Footprint Ratio", 0.7f, _minimumSwampBiomeFootprintRatio); PresetDefaultCheck("Maximum Swamp Inland Retry Distance", 12f, _maxSwampInlandRetryDistance); PresetDefaultCheck("Reject Swamp Card If No Valid Swamp Ground Found", expected: true, _rejectSwampCardIfNoValidGround); PresetDefaultCheck("Maximum Swamp Allowed Shallow Water Depth", 0.2f, _swampMaxShallowWaterDepth); PresetDefaultCheck("Minimum Swamp Root Support Ratio", 0.75f, _minimumSwampRootSupportRatio); PresetDefaultCheck("Minimum Swamp Footprint Support Ratio", 0.65f, _minimumSwampFootprintSupportRatio); PresetDefaultCheck("Handoff Minimum Tree Budget Share", 0.25f, _handoffMinimumTreeBudgetShare); PresetDefaultCheck("Near Minimum Tree Budget Share", 0.2f, _nearMinimumTreeBudgetShare); PresetDefaultCheck("Mid Minimum Tree Budget Share", 0.2f, _midMinimumTreeBudgetShare); PresetDefaultCheck("Far Minimum Tree Budget Share", 0.2f, _farMinimumTreeBudgetShare); PresetDefaultCheck("Horizon Minimum Tree Budget Share", 0.15f, _horizonMinimumTreeBudgetShare); PresetDefaultCheck("Enable Real Clear Skies", expected: true, _enableRealClearSkies); PresetDefaultCheck("Clear Skies Strength", 0.85f, _clearSkiesStrength); PresetDefaultCheck("Allow Occasional Crystal Clear Weather", expected: true, _allowOccasionalCrystalClearWeather); PresetDefaultCheck("Crystal Clear Weather Chance Per Clear Day", 0.2f, _crystalClearChancePerClearDay); PresetDefaultCheck("Crystal Clear Minimum Duration Minutes", 4f, _crystalClearMinimumDurationMinutes); PresetDefaultCheck("Crystal Clear Maximum Duration Minutes", 12f, _crystalClearMaximumDurationMinutes); PresetDefaultCheck("Clear Weather Fog Multiplier", 0.2f, _clearWeatherFogMultiplier); PresetDefaultCheck("Crystal Clear Fog Multiplier", 0.08f, _crystalClearFogMultiplier); PresetDefaultCheck("Clear Weather Cloud Opacity Multiplier", 0.45f, _clearWeatherCloudOpacityMultiplier); PresetDefaultCheck("Crystal Clear Cloud Opacity Multiplier", 0.15f, _crystalClearCloudOpacityMultiplier); PresetDefaultCheck("Clear Weather Horizon Haze Multiplier", 0.25f, _clearWeatherHorizonHazeMultiplier); PresetDefaultCheck("Crystal Clear Horizon Haze Multiplier", 0.08f, _crystalClearHorizonHazeMultiplier); PresetDefaultCheck("Clear Skies Transition Seconds", 10f, _clearSkiesTransitionSeconds); PresetDefaultCheck("Preserve Storm Weather", expected: true, _preserveStormWeather); PresetDefaultCheck("Preserve Rain And Snow", expected: true, _preserveRainAndSnow); PresetDefaultCheck("Preserve Mistlands Mist", expected: true, _preserveMistlandsMist); PresetDefaultCheck("Preserve Ashlands Atmosphere", expected: true, _preserveAshlandsAtmosphere); PresetDefaultCheck("Preserve Deep North Atmosphere", expected: true, _preserveDeepNorthAtmosphere); PresetDefaultCheck("Preserve Boss Weather", expected: true, _preserveBossWeather); PresetDefaultCheck("Restore Original Weather Values On Disable", expected: true, _restoreOriginalWeatherValuesOnDisable); PresetDefaultCheck("Enable Original Distant Land Colour", expected: true, _enableTrueColourDistantLand); PresetDefaultCheck("Original Provider Colour Strength", 1f, _clearWeatherOriginalTerrainColourStrength); PresetDefaultCheck("Atmospheric Colour Strength During Clear Day", 0f, _clearWeatherAtmosphericColourStrength); PresetDefaultCheck("Distance Brightness Loss During Clear Day", 0f, _clearWeatherMaximumTerrainDarkening); PresetDefaultCheck("Distance Saturation Loss During Clear Day", 0f, _clearWeatherDistantSaturationStrength); PresetDefaultCheck("Radial Terrain Colour Transition Width", 500f, _radialTerrainColourTransitionWidth); PresetDefaultCheck("True Colour Blend Seconds", 6f, _trueColourBlendSeconds); PresetDefaultCheck("Use Full Resolution Provider Terrain Colour", expected: true, _useFullResolutionProviderTerrainColour); PresetDefaultCheck("Use Untinted Provider Terrain Colour Map", expected: true, _useUntintedProviderTerrainColourMap); PresetDefaultCheck("Fallback Terrain Colour Texture Resolution", 64, _fallbackTerrainColourTextureResolution); PresetDefaultCheck("Continuity Tile Size", 384f, _continuityTileSize); PresetDefaultCheck("Enable Far Chunk Batching", expected: true, _forestFarChunkMergeEnabled); PresetDefaultCheck("Mid Chunk Size", 96f, _midForestChunkSize); PresetDefaultCheck("Far Chunk Size", 128f, _forestFarChunkSize); PresetDefaultCheck("Far Chunk Merge Start Beyond H", 2500f, _forestFarChunkMergeStart); PresetDefaultCheck("Enable Very Far Chunk Batching", expected: true, _forestVeryFarChunkMergeEnabled); PresetDefaultCheck("Very Far Chunk Size", 160f, _forestVeryFarChunkSize); PresetDefaultCheck("Very Far Chunk Merge Start Beyond H", 6000f, _forestVeryFarChunkMergeStart); PresetDefaultCheck("Tree Material Update Interval Seconds", 0.25f, _minimumTreeMaterialUpdateIntervalSeconds); PresetDefaultCheck("Minimum Brightness Change Before Update", 0.02f, _minimumBrightnessChangeBeforeUpdate); PresetDefaultCheck("Visibility Update Interval Seconds", 0.1f, _visibilityUpdateIntervalSeconds); PresetDefaultCheck("Enable Far Single Plane LOD", expected: true, _enableFarSinglePlaneLod); PresetDefaultCheck("Far Single Plane LOD Start Distance", 1400f, _farSinglePlaneLodStartDistance); PresetDefaultCheck("Horizon Single Plane LOD Start Distance", 2600f, _horizonSinglePlaneLodStartDistance); PresetDefaultCheck("Enable View-Facing Forest Overload Guard", expected: true, _enableViewFacingForestOverloadGuard); PresetDefaultCheck("Visible Detailed Triangle Soft Limit", 220000, _visibleDetailedTriangleSoftLimit); PresetDefaultCheck("Visible Detailed Triangle Hard Limit", 320000, _visibleDetailedTriangleHardLimit); PresetDefaultCheck("Visible Tree Renderer Soft Limit", 450, _visibleTreeRendererSoftLimit); PresetDefaultCheck("Visible Tree Renderer Hard Limit", 650, _visibleTreeRendererHardLimit); PresetDefaultCheck("Mountain Tree Height Multiplier", 3.5f, _mountainTreeHeightMultiplier); PresetDefaultCheck("Mountain Tree Width Multiplier", 3f, _mountainTreeWidthMultiplier); PresetDefaultCheck("Mountain Minimum Random Scale", 0.92f, _mountainMinimumRandomScale); PresetDefaultCheck("Mountain Maximum Random Scale", 1.22f, _mountainMaximumRandomScale); PresetDefaultCheck("Mountain Minimum Width To Height Ratio", 0.5f, _mountainMinimumWidthToHeightRatio); PresetDefaultCheck("Mountain Maximum Width To Height Ratio", 0.78f, _mountainMaximumWidthToHeightRatio); PresetDefaultCheck("Mountain Minimum Automatic Width Scale", 0.78f, _mountainMinimumAutomaticWidthScale); PresetDefaultCheck("Maximum Mountain Ground Card Width", 42f, _maximumMountainGroundCardWidth); PresetDefaultCheck("Black Forest Tree Height Multiplier", 4f, _blackForestTreeHeightMultiplier); PresetDefaultCheck("Black Forest Tree Width Multiplier", 4.25f, _blackForestTreeWidthMultiplier); PresetDefaultCheck("Black Forest Minimum Random Scale", 0.92f, _blackForestMinimumRandomScale); PresetDefaultCheck("Black Forest Maximum Random Scale", 1.25f, _blackForestMaximumRandomScale); PresetDefaultCheck("Black Forest Minimum Width To Height Ratio", 0.6f, _blackForestMinimumWidthToHeightRatio); PresetDefaultCheck("Black Forest Maximum Width To Height Ratio", 0.92f, _blackForestMaximumWidthToHeightRatio); PresetDefaultCheck("Maximum Black Forest Ground Card Width", 48f, _maximumBlackForestGroundCardWidth); PresetDefaultCheck("Black Forest Minimum Automatic Width Scale", 0.8f, _blackForestMinimumAutomaticWidthScale); PresetDefaultCheck("Enable Adaptive High Preset Governor", expected: true, _enableAdaptiveHighPresetGovernor); PresetDefaultCheck("Target Frame Time Ms", 16.67f, _adaptiveTargetFrameTimeMs); PresetDefaultCheck("Soft Frame Time Ms", 22.22f, _adaptiveSoftFrameTimeMs); PresetDefaultCheck("Hard Frame Time Ms", 33.33f, _adaptiveHardFrameTimeMs); PresetDefaultCheck("Terrain Build Interval Frames", 4, _adaptiveTerrainBuildIntervalFrames); PresetDefaultCheck("Preserve Original Colour Near Handoff", expected: true, _preserveOriginalColourNearHandoff); PresetDefaultCheck("Near Handoff Colour Band Width", 800f, _nearHandoffColourBandWidth); PresetDefaultCheck("Near Handoff Daylight Original Colour Strength", 1f, _nearHandoffDaylightOriginalColourStrength); PresetDefaultCheck("Use Neutral Atlas Normals", expected: true, _useNeutralAtlasNormals); PresetDefaultCheck("Near Handoff Weather Colour Influence", 0.05f, _nearHandoffWeatherColourInfluence); PresetDefaultCheck("Near Handoff Fog Colour Influence", 0f, _nearHandoffFogColourInfluence); PresetDefaultCheck("Natural Daylight Darkening", expected: true, _naturalDaylightDarkening); PresetDefaultCheck("Daylight Tree Brightness", 1f, _daylightTreeBrightness); PresetDefaultCheck("Late Afternoon Tree Brightness", 0.9f, _lateAfternoonTreeBrightness); PresetDefaultCheck("Sunset Tree Brightness", 0.75f, _sunsetTreeBrightness); PresetDefaultCheck("Twilight Tree Brightness", 0.55f, _twilightTreeBrightness); PresetDefaultCheck("Night Tree Brightness", 0.3f, _nightTreeBrightness); PresetDefaultCheck("Moonlit Night Tree Brightness", 0.4f, _moonlitNightTreeBrightness); PresetDefaultCheck("Overcast Tree Brightness", 0.7f, _overcastTreeBrightness); PresetDefaultCheck("Storm Tree Brightness", 0.45f, _stormTreeBrightness); PresetDefaultCheck("Minimum Tree Luminance", 0.12f, _minimumTreeLuminance); PresetDefaultCheck("Biome Colour Preservation", 0.9f, _biomeColourPreservation); PresetDefaultCheck("Weather Colour Influence", 0.1f, _weatherColourInfluence); PresetDefaultCheck("Lighting Transition Seconds", 5f, _lightingTransitionSeconds); PresetDefaultCheck("Near Handoff Minimum Alpha", 0.95f, _nearHandoffMinimumAlpha); PresetDefaultCheck("Mid Distance Minimum Alpha", 0.85f, _midDistanceMinimumAlpha); PresetDefaultCheck("Far Distance Minimum Alpha", 0.65f, _farDistanceMinimumAlpha); PresetDefaultCheck("Horizon Minimum Alpha", 0.45f, _horizonMinimumAlpha); object obj = ((_clearSkiesOperatingMode != null) ? ((ConfigEntryBase)_clearSkiesOperatingMode).DefaultValue : null); if (!(obj is ClearSkiesOperatingMode) || (ClearSkiesOperatingMode)obj != ClearSkiesOperatingMode.NaturalWeatherAndOccasionalEvent) { PresetContractViolation("defaults", "Clear Skies Operating Mode=NaturalWeatherAndOccasionalEvent", (obj != null) ? obj.ToString() : "null", "Config.Bind default"); } string a = SharedPresetInvariantSignature(array2[0]); for (int k = 0; k < array2.Length; k++) { string text = SharedPresetInvariantSignature(array2[k]); if (!string.Equals(a, text, StringComparison.Ordinal)) { PresetContractViolation(array2[k].ToString(), "unchanged local density/biomes/appearance/grounding/weather/terrain/lighting/native H", text, "SharedPresetInvariantSignature"); } } float num = NativeTreelineHandoff(); float num2 = EffectiveTreeCardStart(); float num3 = ValidForestRange(); for (int l = 0; l < array2.Length; l++) { string presetContractFailureDetail = _presetContractFailureDetail; PresetRuntimeProfile presetRuntimeProfile = ProfileForPreset(array2[l]); if (presetRuntimeProfile == null) { PresetContractViolation(array2[l].ToString(), "profile", "null", "ProfileForPreset"); continue; } float num4 = (presetRuntimeProfile.UseWorldMaximum ? Mathf.Max(0f, num3 - num) : presetRuntimeProfile.ExtensionDistance); float num5 = (presetRuntimeProfile.UseWorldMaximum ? Mathf.Max(0f, num3 - num) : array3[l]); float num6 = Mathf.Min(num + num4, num3); float num7 = Mathf.Min(num + num5, num3); float actual = Mathf.Min(num6, num + num4 * 0.85f); PresetContractCheck(array2[l], "TreeStart", Mathf.Max(0f, num - NativeTreelineSeamOverlap()), num2, "EffectiveTreeCardStart"); PresetContractCheck(array2[l], "CanopyStart", num2 + CanopyHandoffOffset(), CanopyStart(), "CanopyStart"); PresetContractCheck(array2[l], "Extension E", num5, num4, "PresetRuntimeProfile.ExtensionDistance/UseWorldMaximum"); PresetContractCheck(array2[l], "FinalOuterRange", num7, num6, "min(H + E, ValidForestRange)"); PresetContractCheck(array2[l], "DetailedTreeEnd", Mathf.Min(num7, num + num5 * 0.85f), actual, "H + E * 0.85"); PresetContractCheck(array2[l], "MaximumForestTiles", array4[l], presetRuntimeProfile.MaximumForestTiles, "PresetRuntimeProfile.MaximumForestTiles"); PresetContractCheck(array2[l], "GlobalTreeCardPlaneBudget", array5[l], presetRuntimeProfile.GlobalTreeCardPlaneBudget, "PresetRuntimeProfile.GlobalTreeCardPlaneBudget"); PresetContractCheck(array2[l], "GlobalCanopyPlaneBudget", array6[l], presetRuntimeProfile.GlobalCanopyPlaneBudget, "PresetRuntimeProfile.GlobalCanopyPlaneBudget"); PresetContractCheck(array2[l], "PanicTileCeiling", array7[l], presetRuntimeProfile.PanicTileCeiling, "PresetRuntimeProfile.PanicTileCeiling"); PresetContractCheck(array2[l], "TilesBuiltPerFrame", array8[l], presetRuntimeProfile.TilesBuiltPerFrame, "PresetRuntimeProfile.TilesBuiltPerFrame"); PresetContractCheck(array2[l], "MaximumMeshUploadsPerFrame", array9[l], presetRuntimeProfile.MaximumMeshUploadsPerFrame, "PresetRuntimeProfile.MaximumMeshUploadsPerFrame"); if (num < 499.5f && num2 >= 499.5f) { PresetContractViolation(array2[l].ToString(), "no 500m/550m TREE start floor", num2.ToString("F1", CultureInfo.InvariantCulture), "EffectiveTreeCardStart"); } if (string.Equals(presetContractFailureDetail, _presetContractFailureDetail, StringComparison.Ordinal)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("PRESET CONTRACT VALID — " + array2[l])); } } } private void PresetDefaultCheck(string name, float expected, ConfigEntry entry) { float num = ((entry != null && ((ConfigEntryBase)entry).DefaultValue is float) ? ((float)((ConfigEntryBase)entry).DefaultValue) : float.NaN); if (Mathf.Abs(expected - num) > 0.0001f) { PresetContractViolation("defaults", name + "=" + expected.ToString("R", CultureInfo.InvariantCulture), name + "=" + num.ToString("R", CultureInfo.InvariantCulture), "Config.Bind default"); } } private void PresetDefaultCheck(string name, int expected, ConfigEntry entry) { int num = ((entry != null && ((ConfigEntryBase)entry).DefaultValue is int) ? ((int)((ConfigEntryBase)entry).DefaultValue) : int.MinValue); if (expected != num) { PresetContractViolation("defaults", name + "=" + expected, name + "=" + num, "Config.Bind default"); } } private void PresetDefaultCheck(string name, bool expected, ConfigEntry entry) { bool flag = entry != null && ((ConfigEntryBase)entry).DefaultValue is bool && (bool)((ConfigEntryBase)entry).DefaultValue; if (expected != flag) { PresetContractViolation("defaults", name + "=" + expected, name + "=" + flag, "Config.Bind default"); } } private string SharedPresetInvariantSignature(QualityPreset preset) { if (!Enum.IsDefined(typeof(QualityPreset), preset)) { return "invalid-preset"; } return string.Join("|", NativeTreelineHandoff().ToString("R", CultureInfo.InvariantCulture), NativeTreelineSeamOverlap().ToString("R", CultureInfo.InvariantCulture), ClusterCellSize().ToString("R", CultureInfo.InvariantCulture), MaximumClustersPerTile().ToString(CultureInfo.InvariantCulture), MaxTreeCardPlanesPerTile().ToString(CultureInfo.InvariantCulture), MaxCanopyPlanesPerTile().ToString(CultureInfo.InvariantCulture), ForestDensityMultiplier().ToString("R", CultureInfo.InvariantCulture), ForestDensityThreshold().ToString("R", CultureInfo.InvariantCulture), BiomeForestMultiplier((Biome)1).ToString("R", CultureInfo.InvariantCulture), BiomeForestMultiplier((Biome)8).ToString("R", CultureInfo.InvariantCulture), BiomeForestMultiplier((Biome)2).ToString("R", CultureInfo.InvariantCulture), BiomeForestMultiplier((Biome)4).ToString("R", CultureInfo.InvariantCulture), BiomeForestMultiplier((Biome)16).ToString("R", CultureInfo.InvariantCulture), BiomeForestMultiplier((Biome)512).ToString("R", CultureInfo.InvariantCulture), BiomeForestMultiplier((Biome)32).ToString("R", CultureInfo.InvariantCulture), BiomeForestMultiplier((Biome)64).ToString("R", CultureInfo.InvariantCulture), BiomeCanopyDensityMultiplier((Biome)1).ToString("R", CultureInfo.InvariantCulture), BiomeCanopyDensityMultiplier((Biome)8).ToString("R", CultureInfo.InvariantCulture), BiomeCanopyDensityMultiplier((Biome)2).ToString("R", CultureInfo.InvariantCulture), BiomeCanopyDensityMultiplier((Biome)4).ToString("R", CultureInfo.InvariantCulture), BiomeCanopyDensityMultiplier((Biome)16).ToString("R", CultureInfo.InvariantCulture), BiomeCanopyDensityMultiplier((Biome)512).ToString("R", CultureInfo.InvariantCulture), FarTreeAlpha().ToString("R", CultureInfo.InvariantCulture), FarCanopyAlpha().ToString("R", CultureInfo.InvariantCulture), (_enableStrictFinalHeightmapValidation != null && _enableStrictFinalHeightmapValidation.Value).ToString(), (_rejectGroundCardsOverOpenWater != null && _rejectGroundCardsOverOpenWater.Value).ToString(), (_enableRealClearSkies != null && _enableRealClearSkies.Value).ToString(), (_enableTrueColourDistantLand != null && _enableTrueColourDistantLand.Value).ToString(), (_naturalDaylightDarkening != null && _naturalDaylightDarkening.Value).ToString(), (_enableFarTerrain != null && _enableFarTerrain.Value).ToString()); } private void PresetContractCheck(QualityPreset preset, string valueName, float expected, float actual, string accessor) { if (Mathf.Abs(expected - actual) > 0.001f) { PresetContractViolation(preset.ToString(), valueName + "=" + expected.ToString("R", CultureInfo.InvariantCulture), valueName + "=" + actual.ToString("R", CultureInfo.InvariantCulture), accessor); } } private void PresetContractCheck(QualityPreset preset, string valueName, int expected, int actual, string accessor) { if (expected != actual) { PresetContractViolation(preset.ToString(), valueName + "=" + expected.ToString(CultureInfo.InvariantCulture), valueName + "=" + actual.ToString(CultureInfo.InvariantCulture), accessor); } } private void PresetContractViolation(string preset, string expected, string actual, string accessor) { _presetContractValid = false; string text = "Preset=" + preset + " | expected " + expected + " | actual " + actual + " | source " + accessor; _presetContractFailureDetail = ((_presetContractFailureDetail == "none") ? text : (_presetContractFailureDetail + "; " + text)); ((BaseUnityPlugin)this).Logger.LogError((object)("PRESET CONTRACT VIOLATION -- " + text)); } private void BindConfig() { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Expected O, but got Unknown //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Expected O, but got Unknown //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Expected O, but got Unknown //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Expected O, but got Unknown //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Expected O, but got Unknown //IL_042a: Unknown result type (might be due to invalid IL or missing references) //IL_0434: Expected O, but got Unknown //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_0472: Expected O, but got Unknown //IL_04a6: Unknown result type (might be due to invalid IL or missing references) //IL_04b0: Expected O, but got Unknown //IL_04e4: Unknown result type (might be due to invalid IL or missing references) //IL_04ee: Expected O, but got Unknown //IL_0522: Unknown result type (might be due to invalid IL or missing references) //IL_052c: Expected O, but got Unknown //IL_0560: Unknown result type (might be due to invalid IL or missing references) //IL_056a: Expected O, but got Unknown //IL_05bf: Unknown result type (might be due to invalid IL or missing references) //IL_05c9: Expected O, but got Unknown //IL_05fd: Unknown result type (might be due to invalid IL or missing references) //IL_0607: Expected O, but got Unknown //IL_065c: Unknown result type (might be due to invalid IL or missing references) //IL_0666: Expected O, but got Unknown //IL_069a: Unknown result type (might be due to invalid IL or missing references) //IL_06a4: Expected O, but got Unknown //IL_06d8: Unknown result type (might be due to invalid IL or missing references) //IL_06e2: Expected O, but got Unknown //IL_0716: Unknown result type (might be due to invalid IL or missing references) //IL_0720: Expected O, but got Unknown //IL_07b7: Unknown result type (might be due to invalid IL or missing references) //IL_07c1: Expected O, but got Unknown //IL_07f5: Unknown result type (might be due to invalid IL or missing references) //IL_07ff: Expected O, but got Unknown //IL_0833: Unknown result type (might be due to invalid IL or missing references) //IL_083d: Expected O, but got Unknown //IL_0871: Unknown result type (might be due to invalid IL or missing references) //IL_087b: Expected O, but got Unknown //IL_08af: Unknown result type (might be due to invalid IL or missing references) //IL_08b9: Expected O, but got Unknown //IL_08ed: Unknown result type (might be due to invalid IL or missing references) //IL_08f7: Expected O, but got Unknown //IL_092b: Unknown result type (might be due to invalid IL or missing references) //IL_0935: Expected O, but got Unknown //IL_0969: Unknown result type (might be due to invalid IL or missing references) //IL_0973: Expected O, but got Unknown //IL_09a7: Unknown result type (might be due to invalid IL or missing references) //IL_09b1: Expected O, but got Unknown //IL_09e5: Unknown result type (might be due to invalid IL or missing references) //IL_09ef: Expected O, but got Unknown //IL_0a23: Unknown result type (might be due to invalid IL or missing references) //IL_0a2d: Expected O, but got Unknown //IL_0a61: Unknown result type (might be due to invalid IL or missing references) //IL_0a6b: Expected O, but got Unknown //IL_0a9f: Unknown result type (might be due to invalid IL or missing references) //IL_0aa9: Expected O, but got Unknown //IL_0add: Unknown result type (might be due to invalid IL or missing references) //IL_0ae7: Expected O, but got Unknown //IL_0b1b: Unknown result type (might be due to invalid IL or missing references) //IL_0b25: Expected O, but got Unknown //IL_0b59: Unknown result type (might be due to invalid IL or missing references) //IL_0b63: Expected O, but got Unknown //IL_0b97: Unknown result type (might be due to invalid IL or missing references) //IL_0ba1: Expected O, but got Unknown //IL_0bd5: Unknown result type (might be due to invalid IL or missing references) //IL_0bdf: Expected O, but got Unknown //IL_0c07: Unknown result type (might be due to invalid IL or missing references) //IL_0c11: Expected O, but got Unknown //IL_0c3a: Unknown result type (might be due to invalid IL or missing references) //IL_0c44: Expected O, but got Unknown //IL_0c99: Unknown result type (might be due to invalid IL or missing references) //IL_0ca3: Expected O, but got Unknown //IL_0ccd: Unknown result type (might be due to invalid IL or missing references) //IL_0cd7: Expected O, but got Unknown //IL_0cff: Unknown result type (might be due to invalid IL or missing references) //IL_0d09: Expected O, but got Unknown //IL_0d31: Unknown result type (might be due to invalid IL or missing references) //IL_0d3b: Expected O, but got Unknown //IL_0d90: Unknown result type (might be due to invalid IL or missing references) //IL_0d9a: Expected O, but got Unknown //IL_0dce: Unknown result type (might be due to invalid IL or missing references) //IL_0dd8: Expected O, but got Unknown //IL_0e0c: Unknown result type (might be due to invalid IL or missing references) //IL_0e16: Expected O, but got Unknown //IL_0e43: Unknown result type (might be due to invalid IL or missing references) //IL_0e4d: Expected O, but got Unknown //IL_0e75: Unknown result type (might be due to invalid IL or missing references) //IL_0e7f: Expected O, but got Unknown //IL_0ea7: Unknown result type (might be due to invalid IL or missing references) //IL_0eb1: Expected O, but got Unknown //IL_0ed9: Unknown result type (might be due to invalid IL or missing references) //IL_0ee3: Expected O, but got Unknown //IL_0f17: Unknown result type (might be due to invalid IL or missing references) //IL_0f21: Expected O, but got Unknown //IL_0f55: Unknown result type (might be due to invalid IL or missing references) //IL_0f5f: Expected O, but got Unknown //IL_0f89: Unknown result type (might be due to invalid IL or missing references) //IL_0f93: Expected O, but got Unknown //IL_0fbc: Unknown result type (might be due to invalid IL or missing references) //IL_0fc6: Expected O, but got Unknown //IL_0ff0: Unknown result type (might be due to invalid IL or missing references) //IL_0ffa: Expected O, but got Unknown //IL_1091: Unknown result type (might be due to invalid IL or missing references) //IL_109b: Expected O, but got Unknown //IL_10cf: Unknown result type (might be due to invalid IL or missing references) //IL_10d9: Expected O, but got Unknown //IL_110d: Unknown result type (might be due to invalid IL or missing references) //IL_1117: Expected O, but got Unknown //IL_114b: Unknown result type (might be due to invalid IL or missing references) //IL_1155: Expected O, but got Unknown //IL_1189: Unknown result type (might be due to invalid IL or missing references) //IL_1193: Expected O, but got Unknown //IL_11c7: Unknown result type (might be due to invalid IL or missing references) //IL_11d1: Expected O, but got Unknown //IL_1205: Unknown result type (might be due to invalid IL or missing references) //IL_120f: Expected O, but got Unknown //IL_1264: Unknown result type (might be due to invalid IL or missing references) //IL_126e: Expected O, but got Unknown //IL_12a2: Unknown result type (might be due to invalid IL or missing references) //IL_12ac: Expected O, but got Unknown //IL_12e0: Unknown result type (might be due to invalid IL or missing references) //IL_12ea: Expected O, but got Unknown //IL_1314: Unknown result type (might be due to invalid IL or missing references) //IL_131e: Expected O, but got Unknown //IL_1352: Unknown result type (might be due to invalid IL or missing references) //IL_135c: Expected O, but got Unknown //IL_1390: Unknown result type (might be due to invalid IL or missing references) //IL_139a: Expected O, but got Unknown //IL_13ce: Unknown result type (might be due to invalid IL or missing references) //IL_13d8: Expected O, but got Unknown //IL_1431: Unknown result type (might be due to invalid IL or missing references) //IL_143b: Expected O, but got Unknown //IL_14b1: Unknown result type (might be due to invalid IL or missing references) //IL_14bb: Expected O, but got Unknown //IL_14ef: Unknown result type (might be due to invalid IL or missing references) //IL_14f9: Expected O, but got Unknown //IL_152d: Unknown result type (might be due to invalid IL or missing references) //IL_1537: Expected O, but got Unknown //IL_156b: Unknown result type (might be due to invalid IL or missing references) //IL_1575: Expected O, but got Unknown //IL_15a9: Unknown result type (might be due to invalid IL or missing references) //IL_15b3: Expected O, but got Unknown //IL_15e7: Unknown result type (might be due to invalid IL or missing references) //IL_15f1: Expected O, but got Unknown //IL_1625: Unknown result type (might be due to invalid IL or missing references) //IL_162f: Expected O, but got Unknown //IL_1663: Unknown result type (might be due to invalid IL or missing references) //IL_166d: Expected O, but got Unknown //IL_16a1: Unknown result type (might be due to invalid IL or missing references) //IL_16ab: Expected O, but got Unknown //IL_1700: Unknown result type (might be due to invalid IL or missing references) //IL_170a: Expected O, but got Unknown //IL_173e: Unknown result type (might be due to invalid IL or missing references) //IL_1748: Expected O, but got Unknown //IL_177c: Unknown result type (might be due to invalid IL or missing references) //IL_1786: Expected O, but got Unknown //IL_17ba: Unknown result type (might be due to invalid IL or missing references) //IL_17c4: Expected O, but got Unknown //IL_17f8: Unknown result type (might be due to invalid IL or missing references) //IL_1802: Expected O, but got Unknown //IL_1857: Unknown result type (might be due to invalid IL or missing references) //IL_1861: Expected O, but got Unknown //IL_18b6: Unknown result type (might be due to invalid IL or missing references) //IL_18c0: Expected O, but got Unknown //IL_1915: Unknown result type (might be due to invalid IL or missing references) //IL_191f: Expected O, but got Unknown //IL_1953: Unknown result type (might be due to invalid IL or missing references) //IL_195d: Expected O, but got Unknown //IL_1991: Unknown result type (might be due to invalid IL or missing references) //IL_199b: Expected O, but got Unknown //IL_19cf: Unknown result type (might be due to invalid IL or missing references) //IL_19d9: Expected O, but got Unknown //IL_1a32: Unknown result type (might be due to invalid IL or missing references) //IL_1a3c: Expected O, but got Unknown //IL_1a70: Unknown result type (might be due to invalid IL or missing references) //IL_1a7a: Expected O, but got Unknown //IL_1aae: Unknown result type (might be due to invalid IL or missing references) //IL_1ab8: Expected O, but got Unknown //IL_1aec: Unknown result type (might be due to invalid IL or missing references) //IL_1af6: Expected O, but got Unknown //IL_1b2a: Unknown result type (might be due to invalid IL or missing references) //IL_1b34: Expected O, but got Unknown //IL_1b68: Unknown result type (might be due to invalid IL or missing references) //IL_1b72: Expected O, but got Unknown //IL_1ba6: Unknown result type (might be due to invalid IL or missing references) //IL_1bb0: Expected O, but got Unknown //IL_1be4: Unknown result type (might be due to invalid IL or missing references) //IL_1bee: Expected O, but got Unknown //IL_1c1e: Unknown result type (might be due to invalid IL or missing references) //IL_1c28: Expected O, but got Unknown //IL_1c58: Unknown result type (might be due to invalid IL or missing references) //IL_1c62: Expected O, but got Unknown //IL_1c92: Unknown result type (might be due to invalid IL or missing references) //IL_1c9c: Expected O, but got Unknown //IL_1cd0: Unknown result type (might be due to invalid IL or missing references) //IL_1cda: Expected O, but got Unknown //IL_1d2f: Unknown result type (might be due to invalid IL or missing references) //IL_1d39: Expected O, but got Unknown //IL_1d62: Unknown result type (might be due to invalid IL or missing references) //IL_1d6c: Expected O, but got Unknown //IL_1dc1: Unknown result type (might be due to invalid IL or missing references) //IL_1dcb: Expected O, but got Unknown //IL_1dfb: Unknown result type (might be due to invalid IL or missing references) //IL_1e05: Expected O, but got Unknown //IL_1e35: Unknown result type (might be due to invalid IL or missing references) //IL_1e3f: Expected O, but got Unknown //IL_1e73: Unknown result type (might be due to invalid IL or missing references) //IL_1e7d: Expected O, but got Unknown //IL_1ead: Unknown result type (might be due to invalid IL or missing references) //IL_1eb7: Expected O, but got Unknown //IL_1ee7: Unknown result type (might be due to invalid IL or missing references) //IL_1ef1: Expected O, but got Unknown //IL_1f46: Unknown result type (might be due to invalid IL or missing references) //IL_1f50: Expected O, but got Unknown //IL_1f84: Unknown result type (might be due to invalid IL or missing references) //IL_1f8e: Expected O, but got Unknown //IL_1fc2: Unknown result type (might be due to invalid IL or missing references) //IL_1fcc: Expected O, but got Unknown //IL_2000: Unknown result type (might be due to invalid IL or missing references) //IL_200a: Expected O, but got Unknown //IL_203e: Unknown result type (might be due to invalid IL or missing references) //IL_2048: Expected O, but got Unknown //IL_207c: Unknown result type (might be due to invalid IL or missing references) //IL_2086: Expected O, but got Unknown //IL_20ba: Unknown result type (might be due to invalid IL or missing references) //IL_20c4: Expected O, but got Unknown //IL_20f8: Unknown result type (might be due to invalid IL or missing references) //IL_2102: Expected O, but got Unknown //IL_2136: Unknown result type (might be due to invalid IL or missing references) //IL_2140: Expected O, but got Unknown //IL_2174: Unknown result type (might be due to invalid IL or missing references) //IL_217e: Expected O, but got Unknown //IL_21d3: Unknown result type (might be due to invalid IL or missing references) //IL_21dd: Expected O, but got Unknown //IL_2211: Unknown result type (might be due to invalid IL or missing references) //IL_221b: Expected O, but got Unknown //IL_224f: Unknown result type (might be due to invalid IL or missing references) //IL_2259: Expected O, but got Unknown //IL_228d: Unknown result type (might be due to invalid IL or missing references) //IL_2297: Expected O, but got Unknown //IL_22ec: Unknown result type (might be due to invalid IL or missing references) //IL_22f6: Expected O, but got Unknown //IL_231e: Unknown result type (might be due to invalid IL or missing references) //IL_2328: Expected O, but got Unknown //IL_2351: Unknown result type (might be due to invalid IL or missing references) //IL_235b: Expected O, but got Unknown //IL_238f: Unknown result type (might be due to invalid IL or missing references) //IL_2399: Expected O, but got Unknown //IL_23cd: Unknown result type (might be due to invalid IL or missing references) //IL_23d7: Expected O, but got Unknown //IL_240b: Unknown result type (might be due to invalid IL or missing references) //IL_2415: Expected O, but got Unknown //IL_2449: Unknown result type (might be due to invalid IL or missing references) //IL_2453: Expected O, but got Unknown //IL_2487: Unknown result type (might be due to invalid IL or missing references) //IL_2491: Expected O, but got Unknown //IL_24ba: Unknown result type (might be due to invalid IL or missing references) //IL_24c4: Expected O, but got Unknown //IL_24ed: Unknown result type (might be due to invalid IL or missing references) //IL_24f7: Expected O, but got Unknown //IL_2528: Unknown result type (might be due to invalid IL or missing references) //IL_2532: Expected O, but got Unknown //IL_255f: Unknown result type (might be due to invalid IL or missing references) //IL_2569: Expected O, but got Unknown //IL_25be: Unknown result type (might be due to invalid IL or missing references) //IL_25c8: Expected O, but got Unknown //IL_25fc: Unknown result type (might be due to invalid IL or missing references) //IL_2606: Expected O, but got Unknown //IL_263a: Unknown result type (might be due to invalid IL or missing references) //IL_2644: Expected O, but got Unknown //IL_2678: Unknown result type (might be due to invalid IL or missing references) //IL_2682: Expected O, but got Unknown //IL_26b6: Unknown result type (might be due to invalid IL or missing references) //IL_26c0: Expected O, but got Unknown //IL_26f4: Unknown result type (might be due to invalid IL or missing references) //IL_26fe: Expected O, but got Unknown //IL_272b: Unknown result type (might be due to invalid IL or missing references) //IL_2735: Expected O, but got Unknown //IL_275f: Unknown result type (might be due to invalid IL or missing references) //IL_2769: Expected O, but got Unknown //IL_2793: Unknown result type (might be due to invalid IL or missing references) //IL_279d: Expected O, but got Unknown //IL_27ca: Unknown result type (might be due to invalid IL or missing references) //IL_27d4: Expected O, but got Unknown //IL_27fc: Unknown result type (might be due to invalid IL or missing references) //IL_2806: Expected O, but got Unknown //IL_282e: Unknown result type (might be due to invalid IL or missing references) //IL_2838: Expected O, but got Unknown //IL_286c: Unknown result type (might be due to invalid IL or missing references) //IL_2876: Expected O, but got Unknown //IL_289e: Unknown result type (might be due to invalid IL or missing references) //IL_28a8: Expected O, but got Unknown //IL_28d9: Unknown result type (might be due to invalid IL or missing references) //IL_28e3: Expected O, but got Unknown //IL_290b: Unknown result type (might be due to invalid IL or missing references) //IL_2915: Expected O, but got Unknown //IL_296a: Unknown result type (might be due to invalid IL or missing references) //IL_2974: Expected O, but got Unknown //IL_29a8: Unknown result type (might be due to invalid IL or missing references) //IL_29b2: Expected O, but got Unknown //IL_29db: Unknown result type (might be due to invalid IL or missing references) //IL_29e5: Expected O, but got Unknown //IL_2a0e: Unknown result type (might be due to invalid IL or missing references) //IL_2a18: Expected O, but got Unknown //IL_2a6d: Unknown result type (might be due to invalid IL or missing references) //IL_2a77: Expected O, but got Unknown //IL_2a9f: Unknown result type (might be due to invalid IL or missing references) //IL_2aa9: Expected O, but got Unknown //IL_2ad6: Unknown result type (might be due to invalid IL or missing references) //IL_2ae0: Expected O, but got Unknown //IL_2b14: Unknown result type (might be due to invalid IL or missing references) //IL_2b1e: Expected O, but got Unknown //IL_2b52: Unknown result type (might be due to invalid IL or missing references) //IL_2b5c: Expected O, but got Unknown //IL_2b90: Unknown result type (might be due to invalid IL or missing references) //IL_2b9a: Expected O, but got Unknown //IL_2bec: Unknown result type (might be due to invalid IL or missing references) //IL_2bf6: Expected O, but got Unknown //IL_2c27: Unknown result type (might be due to invalid IL or missing references) //IL_2c31: Expected O, but got Unknown //IL_2ca7: Unknown result type (might be due to invalid IL or missing references) //IL_2cb1: Expected O, but got Unknown //IL_2ce2: Unknown result type (might be due to invalid IL or missing references) //IL_2cec: Expected O, but got Unknown //IL_2d20: Unknown result type (might be due to invalid IL or missing references) //IL_2d2a: Expected O, but got Unknown //IL_2d5e: Unknown result type (might be due to invalid IL or missing references) //IL_2d68: Expected O, but got Unknown //IL_2d9c: Unknown result type (might be due to invalid IL or missing references) //IL_2da6: Expected O, but got Unknown //IL_2dfb: Unknown result type (might be due to invalid IL or missing references) //IL_2e05: Expected O, but got Unknown //IL_2e39: Unknown result type (might be due to invalid IL or missing references) //IL_2e43: Expected O, but got Unknown //IL_2e77: Unknown result type (might be due to invalid IL or missing references) //IL_2e81: Expected O, but got Unknown //IL_2ed6: Unknown result type (might be due to invalid IL or missing references) //IL_2ee0: Expected O, but got Unknown //IL_2f14: Unknown result type (might be due to invalid IL or missing references) //IL_2f1e: Expected O, but got Unknown //IL_2f58: Unknown result type (might be due to invalid IL or missing references) //IL_2f62: Expected O, but got Unknown //IL_2f96: Unknown result type (might be due to invalid IL or missing references) //IL_2fa0: Expected O, but got Unknown //IL_2fd4: Unknown result type (might be due to invalid IL or missing references) //IL_2fde: Expected O, but got Unknown //IL_3033: Unknown result type (might be due to invalid IL or missing references) //IL_303d: Expected O, but got Unknown //IL_3071: Unknown result type (might be due to invalid IL or missing references) //IL_307b: Expected O, but got Unknown //IL_30d0: Unknown result type (might be due to invalid IL or missing references) //IL_30da: Expected O, but got Unknown //IL_310e: Unknown result type (might be due to invalid IL or missing references) //IL_3118: Expected O, but got Unknown //IL_3149: Unknown result type (might be due to invalid IL or missing references) //IL_3153: Expected O, but got Unknown //IL_3184: Unknown result type (might be due to invalid IL or missing references) //IL_318e: Expected O, but got Unknown //IL_31e3: Unknown result type (might be due to invalid IL or missing references) //IL_31ed: Expected O, but got Unknown //IL_3221: Unknown result type (might be due to invalid IL or missing references) //IL_322b: Expected O, but got Unknown //IL_325f: Unknown result type (might be due to invalid IL or missing references) //IL_3269: Expected O, but got Unknown //IL_3296: Unknown result type (might be due to invalid IL or missing references) //IL_32a0: Expected O, but got Unknown //IL_32d4: Unknown result type (might be due to invalid IL or missing references) //IL_32de: Expected O, but got Unknown //IL_3312: Unknown result type (might be due to invalid IL or missing references) //IL_331c: Expected O, but got Unknown //IL_3350: Unknown result type (might be due to invalid IL or missing references) //IL_335a: Expected O, but got Unknown //IL_3382: Unknown result type (might be due to invalid IL or missing references) //IL_338c: Expected O, but got Unknown //IL_33b5: Unknown result type (might be due to invalid IL or missing references) //IL_33bf: Expected O, but got Unknown //IL_33f3: Unknown result type (might be due to invalid IL or missing references) //IL_33fd: Expected O, but got Unknown //IL_3431: Unknown result type (might be due to invalid IL or missing references) //IL_343b: Expected O, but got Unknown //IL_346f: Unknown result type (might be due to invalid IL or missing references) //IL_3479: Expected O, but got Unknown //IL_34ad: Unknown result type (might be due to invalid IL or missing references) //IL_34b7: Expected O, but got Unknown //IL_34df: Unknown result type (might be due to invalid IL or missing references) //IL_34e9: Expected O, but got Unknown //IL_351d: Unknown result type (might be due to invalid IL or missing references) //IL_3527: Expected O, but got Unknown //IL_355b: Unknown result type (might be due to invalid IL or missing references) //IL_3565: Expected O, but got Unknown //IL_358d: Unknown result type (might be due to invalid IL or missing references) //IL_3597: Expected O, but got Unknown //IL_35cb: Unknown result type (might be due to invalid IL or missing references) //IL_35d5: Expected O, but got Unknown //IL_35fd: Unknown result type (might be due to invalid IL or missing references) //IL_3607: Expected O, but got Unknown //IL_363b: Unknown result type (might be due to invalid IL or missing references) //IL_3645: Expected O, but got Unknown //IL_366d: Unknown result type (might be due to invalid IL or missing references) //IL_3677: Expected O, but got Unknown //IL_36cc: Unknown result type (might be due to invalid IL or missing references) //IL_36d6: Expected O, but got Unknown //IL_370a: Unknown result type (might be due to invalid IL or missing references) //IL_3714: Expected O, but got Unknown //IL_373d: Unknown result type (might be due to invalid IL or missing references) //IL_3747: Expected O, but got Unknown //IL_379c: Unknown result type (might be due to invalid IL or missing references) //IL_37a6: Expected O, but got Unknown //IL_37da: Unknown result type (might be due to invalid IL or missing references) //IL_37e4: Expected O, but got Unknown //IL_3818: Unknown result type (might be due to invalid IL or missing references) //IL_3822: Expected O, but got Unknown //IL_3856: Unknown result type (might be due to invalid IL or missing references) //IL_3860: Expected O, but got Unknown //IL_38b5: Unknown result type (might be due to invalid IL or missing references) //IL_38bf: Expected O, but got Unknown //IL_3935: Unknown result type (might be due to invalid IL or missing references) //IL_393f: Expected O, but got Unknown //IL_3973: Unknown result type (might be due to invalid IL or missing references) //IL_397d: Expected O, but got Unknown //IL_39b1: Unknown result type (might be due to invalid IL or missing references) //IL_39bb: Expected O, but got Unknown //IL_39ef: Unknown result type (might be due to invalid IL or missing references) //IL_39f9: Expected O, but got Unknown //IL_3a2d: Unknown result type (might be due to invalid IL or missing references) //IL_3a37: Expected O, but got Unknown //IL_3a6b: Unknown result type (might be due to invalid IL or missing references) //IL_3a75: Expected O, but got Unknown //IL_3aa9: Unknown result type (might be due to invalid IL or missing references) //IL_3ab3: Expected O, but got Unknown //IL_3ae7: Unknown result type (might be due to invalid IL or missing references) //IL_3af1: Expected O, but got Unknown //IL_3b25: Unknown result type (might be due to invalid IL or missing references) //IL_3b2f: Expected O, but got Unknown //IL_3b63: Unknown result type (might be due to invalid IL or missing references) //IL_3b6d: Expected O, but got Unknown //IL_3ba1: Unknown result type (might be due to invalid IL or missing references) //IL_3bab: Expected O, but got Unknown //IL_3bdf: Unknown result type (might be due to invalid IL or missing references) //IL_3be9: Expected O, but got Unknown //IL_3d4a: Unknown result type (might be due to invalid IL or missing references) //IL_3d54: Expected O, but got Unknown //IL_3d88: Unknown result type (might be due to invalid IL or missing references) //IL_3d92: Expected O, but got Unknown //IL_3e10: Unknown result type (might be due to invalid IL or missing references) //IL_3e1a: Invalid comparison between Unknown and I4 //IL_4054: Unknown result type (might be due to invalid IL or missing references) //IL_405e: Expected O, but got Unknown //IL_4092: Unknown result type (might be due to invalid IL or missing references) //IL_409c: Expected O, but got Unknown //IL_40cd: Unknown result type (might be due to invalid IL or missing references) //IL_40d7: Expected O, but got Unknown //IL_412c: Unknown result type (might be due to invalid IL or missing references) //IL_4136: Expected O, but got Unknown //IL_41ac: Unknown result type (might be due to invalid IL or missing references) //IL_41b6: Expected O, but got Unknown //IL_422c: Unknown result type (might be due to invalid IL or missing references) //IL_4236: Expected O, but got Unknown //IL_426a: Unknown result type (might be due to invalid IL or missing references) //IL_4274: Expected O, but got Unknown //IL_42a8: Unknown result type (might be due to invalid IL or missing references) //IL_42b2: Expected O, but got Unknown //IL_42e6: Unknown result type (might be due to invalid IL or missing references) //IL_42f0: Expected O, but got Unknown //IL_4430: Unknown result type (might be due to invalid IL or missing references) //IL_443a: Expected O, but got Unknown //IL_446e: Unknown result type (might be due to invalid IL or missing references) //IL_4478: Expected O, but got Unknown //IL_44ac: Unknown result type (might be due to invalid IL or missing references) //IL_44b6: Expected O, but got Unknown //IL_44ea: Unknown result type (might be due to invalid IL or missing references) //IL_44f4: Expected O, but got Unknown //IL_4528: Unknown result type (might be due to invalid IL or missing references) //IL_4532: Expected O, but got Unknown //IL_4587: Unknown result type (might be due to invalid IL or missing references) //IL_4591: Expected O, but got Unknown //IL_45c5: Unknown result type (might be due to invalid IL or missing references) //IL_45cf: Expected O, but got Unknown //IL_4603: Unknown result type (might be due to invalid IL or missing references) //IL_460d: Expected O, but got Unknown //IL_4662: Unknown result type (might be due to invalid IL or missing references) //IL_466c: Expected O, but got Unknown //IL_46a0: Unknown result type (might be due to invalid IL or missing references) //IL_46aa: Expected O, but got Unknown //IL_46de: Unknown result type (might be due to invalid IL or missing references) //IL_46e8: Expected O, but got Unknown //IL_471c: Unknown result type (might be due to invalid IL or missing references) //IL_4726: Expected O, but got Unknown //IL_475a: Unknown result type (might be due to invalid IL or missing references) //IL_4764: Expected O, but got Unknown //IL_47b9: Unknown result type (might be due to invalid IL or missing references) //IL_47c3: Expected O, but got Unknown //IL_4818: Unknown result type (might be due to invalid IL or missing references) //IL_4822: Expected O, but got Unknown //IL_4856: Unknown result type (might be due to invalid IL or missing references) //IL_4860: Expected O, but got Unknown //IL_4894: Unknown result type (might be due to invalid IL or missing references) //IL_489e: Expected O, but got Unknown //IL_48d2: Unknown result type (might be due to invalid IL or missing references) //IL_48dc: Expected O, but got Unknown //IL_4910: Unknown result type (might be due to invalid IL or missing references) //IL_491a: Expected O, but got Unknown //IL_4990: Unknown result type (might be due to invalid IL or missing references) //IL_499a: Expected O, but got Unknown //IL_49ce: Unknown result type (might be due to invalid IL or missing references) //IL_49d8: Expected O, but got Unknown //IL_4a0c: Unknown result type (might be due to invalid IL or missing references) //IL_4a16: Expected O, but got Unknown //IL_4a6b: Unknown result type (might be due to invalid IL or missing references) //IL_4a75: Expected O, but got Unknown //IL_4aa9: Unknown result type (might be due to invalid IL or missing references) //IL_4ab3: Expected O, but got Unknown //IL_4ae7: Unknown result type (might be due to invalid IL or missing references) //IL_4af1: Expected O, but got Unknown //IL_4b25: Unknown result type (might be due to invalid IL or missing references) //IL_4b2f: Expected O, but got Unknown //IL_4b63: Unknown result type (might be due to invalid IL or missing references) //IL_4b6d: Expected O, but got Unknown //IL_4ba1: Unknown result type (might be due to invalid IL or missing references) //IL_4bab: Expected O, but got Unknown //IL_4bdf: Unknown result type (might be due to invalid IL or missing references) //IL_4be9: Expected O, but got Unknown //IL_4c1d: Unknown result type (might be due to invalid IL or missing references) //IL_4c27: Expected O, but got Unknown //IL_4c5b: Unknown result type (might be due to invalid IL or missing references) //IL_4c65: Expected O, but got Unknown //IL_4c99: Unknown result type (might be due to invalid IL or missing references) //IL_4ca3: Expected O, but got Unknown //IL_4cd7: Unknown result type (might be due to invalid IL or missing references) //IL_4ce1: Expected O, but got Unknown //IL_4d15: Unknown result type (might be due to invalid IL or missing references) //IL_4d1f: Expected O, but got Unknown //IL_4d74: Unknown result type (might be due to invalid IL or missing references) //IL_4d7e: Expected O, but got Unknown //IL_4db2: Unknown result type (might be due to invalid IL or missing references) //IL_4dbc: Expected O, but got Unknown //IL_4df0: Unknown result type (might be due to invalid IL or missing references) //IL_4dfa: Expected O, but got Unknown //IL_4e2e: Unknown result type (might be due to invalid IL or missing references) //IL_4e38: Expected O, but got Unknown //IL_4e6c: Unknown result type (might be due to invalid IL or missing references) //IL_4e76: Expected O, but got Unknown //IL_4ee0: Unknown result type (might be due to invalid IL or missing references) //IL_4eea: Expected O, but got Unknown //IL_4f1e: Unknown result type (might be due to invalid IL or missing references) //IL_4f28: Expected O, but got Unknown //IL_4f5c: Unknown result type (might be due to invalid IL or missing references) //IL_4f66: Expected O, but got Unknown //IL_4f9a: Unknown result type (might be due to invalid IL or missing references) //IL_4fa4: Expected O, but got Unknown //IL_4fd8: Unknown result type (might be due to invalid IL or missing references) //IL_4fe2: Expected O, but got Unknown //IL_5016: Unknown result type (might be due to invalid IL or missing references) //IL_5020: Expected O, but got Unknown //IL_5054: Unknown result type (might be due to invalid IL or missing references) //IL_505e: Expected O, but got Unknown //IL_50d4: Unknown result type (might be due to invalid IL or missing references) //IL_50de: Expected O, but got Unknown //IL_5112: Unknown result type (might be due to invalid IL or missing references) //IL_511c: Expected O, but got Unknown //IL_5150: Unknown result type (might be due to invalid IL or missing references) //IL_515a: Expected O, but got Unknown //IL_518e: Unknown result type (might be due to invalid IL or missing references) //IL_5198: Expected O, but got Unknown //IL_51cc: Unknown result type (might be due to invalid IL or missing references) //IL_51d6: Expected O, but got Unknown //IL_520a: Unknown result type (might be due to invalid IL or missing references) //IL_5214: Expected O, but got Unknown //IL_5248: Unknown result type (might be due to invalid IL or missing references) //IL_5252: Expected O, but got Unknown //IL_5286: Unknown result type (might be due to invalid IL or missing references) //IL_5290: Expected O, but got Unknown //IL_52c4: Unknown result type (might be due to invalid IL or missing references) //IL_52ce: Expected O, but got Unknown //IL_5302: Unknown result type (might be due to invalid IL or missing references) //IL_530c: Expected O, but got Unknown //IL_5340: Unknown result type (might be due to invalid IL or missing references) //IL_534a: Expected O, but got Unknown //IL_537e: Unknown result type (might be due to invalid IL or missing references) //IL_5388: Expected O, but got Unknown //IL_53bc: Unknown result type (might be due to invalid IL or missing references) //IL_53c6: Expected O, but got Unknown //IL_53fa: Unknown result type (might be due to invalid IL or missing references) //IL_5404: Expected O, but got Unknown //IL_5438: Unknown result type (might be due to invalid IL or missing references) //IL_5442: Expected O, but got Unknown //IL_5476: Unknown result type (might be due to invalid IL or missing references) //IL_5480: Expected O, but got Unknown //IL_54b4: Unknown result type (might be due to invalid IL or missing references) //IL_54be: Expected O, but got Unknown //IL_54f2: Unknown result type (might be due to invalid IL or missing references) //IL_54fc: Expected O, but got Unknown //IL_5530: Unknown result type (might be due to invalid IL or missing references) //IL_553a: Expected O, but got Unknown //IL_556e: Unknown result type (might be due to invalid IL or missing references) //IL_5578: Expected O, but got Unknown //IL_55ac: Unknown result type (might be due to invalid IL or missing references) //IL_55b6: Expected O, but got Unknown //IL_55ea: Unknown result type (might be due to invalid IL or missing references) //IL_55f4: Expected O, but got Unknown //IL_5628: Unknown result type (might be due to invalid IL or missing references) //IL_5632: Expected O, but got Unknown //IL_5687: Unknown result type (might be due to invalid IL or missing references) //IL_5691: Expected O, but got Unknown //IL_56c5: Unknown result type (might be due to invalid IL or missing references) //IL_56cf: Expected O, but got Unknown //IL_5703: Unknown result type (might be due to invalid IL or missing references) //IL_570d: Expected O, but got Unknown //IL_5741: Unknown result type (might be due to invalid IL or missing references) //IL_574b: Expected O, but got Unknown //IL_577f: Unknown result type (might be due to invalid IL or missing references) //IL_5789: Expected O, but got Unknown //IL_57bd: Unknown result type (might be due to invalid IL or missing references) //IL_57c7: Expected O, but got Unknown //IL_581c: Unknown result type (might be due to invalid IL or missing references) //IL_5826: Expected O, but got Unknown //IL_585a: Unknown result type (might be due to invalid IL or missing references) //IL_5864: Expected O, but got Unknown //IL_5898: Unknown result type (might be due to invalid IL or missing references) //IL_58a2: Expected O, but got Unknown //IL_58d6: Unknown result type (might be due to invalid IL or missing references) //IL_58e0: Expected O, but got Unknown //IL_5914: Unknown result type (might be due to invalid IL or missing references) //IL_591e: Expected O, but got Unknown //IL_5952: Unknown result type (might be due to invalid IL or missing references) //IL_595c: Expected O, but got Unknown //IL_59d2: Unknown result type (might be due to invalid IL or missing references) //IL_59dc: Expected O, but got Unknown //IL_5a10: Unknown result type (might be due to invalid IL or missing references) //IL_5a1a: Expected O, but got Unknown //IL_5a4e: Unknown result type (might be due to invalid IL or missing references) //IL_5a58: Expected O, but got Unknown //IL_5a8c: Unknown result type (might be due to invalid IL or missing references) //IL_5a96: Expected O, but got Unknown //IL_5aca: Unknown result type (might be due to invalid IL or missing references) //IL_5ad4: Expected O, but got Unknown //IL_5b08: Unknown result type (might be due to invalid IL or missing references) //IL_5b12: Expected O, but got Unknown //IL_5b82: Unknown result type (might be due to invalid IL or missing references) //IL_5b8c: Expected O, but got Unknown //IL_5c86: Unknown result type (might be due to invalid IL or missing references) //IL_5c90: Expected O, but got Unknown //IL_5cc4: Unknown result type (might be due to invalid IL or missing references) //IL_5cce: Expected O, but got Unknown //IL_5d02: Unknown result type (might be due to invalid IL or missing references) //IL_5d0c: Expected O, but got Unknown //IL_5d61: Unknown result type (might be due to invalid IL or missing references) //IL_5d6b: Expected O, but got Unknown //IL_5d9f: Unknown result type (might be due to invalid IL or missing references) //IL_5da9: Expected O, but got Unknown //IL_5ddd: Unknown result type (might be due to invalid IL or missing references) //IL_5de7: Expected O, but got Unknown //IL_5e1b: Unknown result type (might be due to invalid IL or missing references) //IL_5e25: Expected O, but got Unknown //IL_5e59: Unknown result type (might be due to invalid IL or missing references) //IL_5e63: Expected O, but got Unknown //IL_5e97: Unknown result type (might be due to invalid IL or missing references) //IL_5ea1: Expected O, but got Unknown //IL_5ed5: Unknown result type (might be due to invalid IL or missing references) //IL_5edf: Expected O, but got Unknown //IL_5f13: Unknown result type (might be due to invalid IL or missing references) //IL_5f1d: Expected O, but got Unknown //IL_5f51: Unknown result type (might be due to invalid IL or missing references) //IL_5f5b: Expected O, but got Unknown //IL_5f8f: Unknown result type (might be due to invalid IL or missing references) //IL_5f99: Expected O, but got Unknown //IL_5fcd: Unknown result type (might be due to invalid IL or missing references) //IL_5fd7: Expected O, but got Unknown //IL_600b: Unknown result type (might be due to invalid IL or missing references) //IL_6015: Expected O, but got Unknown //IL_6049: Unknown result type (might be due to invalid IL or missing references) //IL_6053: Expected O, but got Unknown //IL_6087: Unknown result type (might be due to invalid IL or missing references) //IL_6091: Expected O, but got Unknown //IL_60c5: Unknown result type (might be due to invalid IL or missing references) //IL_60cf: Expected O, but got Unknown //IL_6103: Unknown result type (might be due to invalid IL or missing references) //IL_610d: Expected O, but got Unknown //IL_6141: Unknown result type (might be due to invalid IL or missing references) //IL_614b: Expected O, but got Unknown //IL_617f: Unknown result type (might be due to invalid IL or missing references) //IL_6189: Expected O, but got Unknown //IL_61bd: Unknown result type (might be due to invalid IL or missing references) //IL_61c7: Expected O, but got Unknown //IL_61fb: Unknown result type (might be due to invalid IL or missing references) //IL_6205: Expected O, but got Unknown //IL_6239: Unknown result type (might be due to invalid IL or missing references) //IL_6243: Expected O, but got Unknown //IL_6277: Unknown result type (might be due to invalid IL or missing references) //IL_6281: Expected O, but got Unknown //IL_62b5: Unknown result type (might be due to invalid IL or missing references) //IL_62bf: Expected O, but got Unknown //IL_62f3: Unknown result type (might be due to invalid IL or missing references) //IL_62fd: Expected O, but got Unknown //IL_6331: Unknown result type (might be due to invalid IL or missing references) //IL_633b: Expected O, but got Unknown //IL_636f: Unknown result type (might be due to invalid IL or missing references) //IL_6379: Expected O, but got Unknown //IL_63d4: Unknown result type (might be due to invalid IL or missing references) //IL_63de: Expected O, but got Unknown //IL_6412: Unknown result type (might be due to invalid IL or missing references) //IL_641c: Expected O, but got Unknown //IL_6450: Unknown result type (might be due to invalid IL or missing references) //IL_645a: Expected O, but got Unknown //IL_648e: Unknown result type (might be due to invalid IL or missing references) //IL_6498: Expected O, but got Unknown //IL_64cc: Unknown result type (might be due to invalid IL or missing references) //IL_64d6: Expected O, but got Unknown //IL_650a: Unknown result type (might be due to invalid IL or missing references) //IL_6514: Expected O, but got Unknown //IL_6548: Unknown result type (might be due to invalid IL or missing references) //IL_6552: Expected O, but got Unknown //IL_65c8: Unknown result type (might be due to invalid IL or missing references) //IL_65d2: Expected O, but got Unknown //IL_6627: Unknown result type (might be due to invalid IL or missing references) //IL_6631: Expected O, but got Unknown //IL_6783: Unknown result type (might be due to invalid IL or missing references) //IL_678d: Expected O, but got Unknown //IL_67c1: Unknown result type (might be due to invalid IL or missing references) //IL_67cb: Expected O, but got Unknown //IL_67ff: Unknown result type (might be due to invalid IL or missing references) //IL_6809: Expected O, but got Unknown //IL_683d: Unknown result type (might be due to invalid IL or missing references) //IL_6847: Expected O, but got Unknown //IL_68bd: Unknown result type (might be due to invalid IL or missing references) //IL_68c7: Expected O, but got Unknown //IL_69a0: Unknown result type (might be due to invalid IL or missing references) //IL_69aa: Expected O, but got Unknown //IL_69de: Unknown result type (might be due to invalid IL or missing references) //IL_69e8: Expected O, but got Unknown //IL_6a1c: Unknown result type (might be due to invalid IL or missing references) //IL_6a26: Expected O, but got Unknown //IL_6a70: Unknown result type (might be due to invalid IL or missing references) //IL_6a7a: Expected O, but got Unknown //IL_6aae: Unknown result type (might be due to invalid IL or missing references) //IL_6ab8: Expected O, but got Unknown //IL_6aec: Unknown result type (might be due to invalid IL or missing references) //IL_6af6: Expected O, but got Unknown //IL_6b2a: Unknown result type (might be due to invalid IL or missing references) //IL_6b34: Expected O, but got Unknown //IL_6c70: Unknown result type (might be due to invalid IL or missing references) //IL_6c7a: Expected O, but got Unknown //IL_6cae: Unknown result type (might be due to invalid IL or missing references) //IL_6cb8: Expected O, but got Unknown //IL_6d0d: Unknown result type (might be due to invalid IL or missing references) //IL_6d17: Expected O, but got Unknown //IL_3e55: Unknown result type (might be due to invalid IL or missing references) //IL_3e5f: Invalid comparison between Unknown and I4 string text = Path.Combine("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Valheim_Modded_BACKUP\\DonegalValheimYourThirsty\\Valheim\\profiles\\DonegalHorizons", "BepInEx\\plugins\\JereKuusela-BetterContinents\\custommaps"); string text2 = Path.Combine("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Valheim_Modded_BACKUP\\DonegalValheimYourThirsty\\Valheim\\profiles\\DonegalHorizons", "BepInEx\\config\\BetterContinents.cfg"); string text3 = Path.Combine("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Valheim_Modded_BACKUP\\DonegalValheimYourThirsty\\Valheim\\profiles\\DonegalHorizons", "BepInEx\\config\\render_limits.cfg"); _enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Master switch for the visual-only horizon renderer."); _waitForGameplayWorld = ((BaseUnityPlugin)this).Config.Bind("General", "Wait For Real Gameplay World", true, "Prevents Horizon Lift from binding to Valheim's menu/startup WorldGenerator. The renderer waits until a real player, ZoneSystem and WorldGenerator exist before creating far terrain/forest providers."); _requireWaterSystemForProceduralWorld = ((BaseUnityPlugin)this).Config.Bind("General", "Require Water System For Procedural World", true, "ProceduralWorld provider waits for ZoneSystem water level before it can render. This prevents far tree cards from being validated against an unresolved water surface."); _worldDataMode = ((BaseUnityPlugin)this).Config.Bind("General", "World Data Mode", WorldDataMode.Auto, "Auto keeps Better Continents custom maps when the exact sampler is ready, otherwise uses native ProceduralWorld. BetterContinentsCustomMap and ProceduralWorld force one provider."); _proceduralWorldRadius = ((BaseUnityPlugin)this).Config.Bind("Procedural World", "World Radius", 10500f, new ConfigDescription("Native procedural-world radius in metres. Standard Valheim worlds use 10500. Increase only for a modded generator with a larger real world.", (AcceptableValueBase)(object)new AcceptableValueRange(2000f, 30000f), Array.Empty())); _mapFolder = ((BaseUnityPlugin)this).Config.Bind("Files", "Map Folder", text, "Better Continents custommaps folder containing heightmap.png, forestmap.png and horizoncolormap.png."); _betterContinentsConfigFile = ((BaseUnityPlugin)this).Config.Bind("Files", "Better Continents Config File", text2, "Active BetterContinents.cfg. Read-only."); _renderLimitsConfigFile = ((BaseUnityPlugin)this).Config.Bind("Files", "Render Limits Config File", text3, "Active render_limits.cfg. Read-only; used only to compute a safe native envelope."); _heightMapFile = ((BaseUnityPlugin)this).Config.Bind("Files", "Height Map File", "heightmap.png", "Existing Better Continents height map. Read for validation only; final geometry never directly samples it for height."); _colourMapFile = ((BaseUnityPlugin)this).Config.Bind("Files", "Horizon Colour Map File", "horizoncolormap.png", "RGB terrain colour texture aligned to the Better Continents map."); _forestMapFile = ((BaseUnityPlugin)this).Config.Bind("Files", "Forest Map File", "forestmap.png", "Grayscale forest-density map aligned to the Better Continents map."); _treeAtlasFile = ((BaseUnityPlugin)this).Config.Bind("Files", "Tree Atlas File", "nh_mixed_treeatlas.png", "Runtime mixed tree-card atlas beside DonegalHorizonLift.dll. Falls back to legacy treeatlas.png only if this file is missing or invalid."); _canopyAtlasFile = ((BaseUnityPlugin)this).Config.Bind("Files", "Canopy Atlas File", "nh_mixed_canopyatlas.png", "Runtime mixed canopy/treeline atlas beside DonegalHorizonLift.dll. Falls back to legacy canopyatlas.png only if this file is missing or invalid."); _mountainBiomeAtlasFile = ((BaseUnityPlugin)this).Config.Bind("Files", "Mountain Biome Atlas File", "nh_mountain_biome_atlas.png", "Runtime mountain biome card atlas beside DonegalHorizonLift.dll. Read-only."); _swampBiomeAtlasFile = ((BaseUnityPlugin)this).Config.Bind("Files", "Swamp Biome Atlas File", "nh_swamp_biome_atlas.png", "Runtime swamp biome card atlas beside DonegalHorizonLift.dll. Read-only."); _requireRenderLimits = ((BaseUnityPlugin)this).Config.Bind("Compatibility", "Require Render Limits", false, "Optional integration only. When false (default), Horizon Lift builds geometry without Render Limits, using runtime zone values, the manual radius, or the safe minimum exclusion fallback."); _allowManualEnvelopeWithoutRenderLimits = ((BaseUnityPlugin)this).Config.Bind("Compatibility", "Allow Manual Radius Without Render Limits", true, "When Render Limits is absent, the Manual Near World Exclusion Radius (or the safe minimum fallback) defines the exclusion envelope so geometry still generates."); _manualNearWorldExclusionRadius = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Manual Near World Exclusion Radius", 0f, new ConfigDescription("Metres around the player where Horizon Lift creates no geometry. 0 computes from Render Limits.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 4000f), Array.Empty())); _minimumNearWorldExclusionRadius = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Minimum Near World Exclusion Radius", 500f, new ConfigDescription("Hard minimum safe exclusion radius, after Render Limits calculation.", (AcceptableValueBase)(object)new AcceptableValueRange(500f, 4000f), Array.Empty())); _nativeEnvelopePadding = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Native Envelope Padding", 128f, new ConfigDescription("Extra safety padding added to Render Limits terrain/object distances.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 800f), Array.Empty())); _qualityPreset = ((BaseUnityPlugin)this).Config.Bind("General", "Quality Preset", QualityPreset.Horizon, "VeryLow | Low | Balanced | Medium | High | Ultra | Horizon | Custom. Standard presets select only E and capacity/workload ceilings. They never alter H, TreeStart, local density, biome multipliers, card appearance, grounding, water safety, fog, weather, lighting, or terrain. Legacy Performance/Extreme/Cinematic names are migrated once to VeryLow/Horizon/Ultra."); MigrateLegacyPresetNameOnce(); _autoDetectNativeTreeViewDistance = ((BaseUnityPlugin)this).Config.Bind("Preset Ranges", "Auto Detect Native Tree View Distance", true, "When true and Native Treeline Mode = Auto Detect, Horizon Lift tries to read the active native/tree visibility range (H) before using the fallback below."); _nativeTreeViewDistanceFallback = ((BaseUnityPlugin)this).Config.Bind("Preset Ranges", "Native Tree View Distance Fallback", 215f, new ConfigDescription("Fallback native Valheim tree render distance H. It never overrides ManualCalibrated mode and is not a minimum start floor.", (AcceptableValueBase)(object)new AcceptableValueRange(100f, 4000f), Array.Empty())); _nativeTreelineMode = ((BaseUnityPlugin)this).Config.Bind("Native Treeline", "Native Treeline Mode", NativeTreelineMode.ManualCalibrated, "ManualCalibrated (release default) uses the saved Native Treeline Calibrated Radius as exact H and ignores every legacy fallback/start/exclusion/camera value. AutoDetect reads a dedicated tree/vegetation key. DefaultFallback uses only the fallback value."); _nativeTreelineCalibratedRadius = ((BaseUnityPlugin)this).Config.Bind("Native Treeline", "Native Treeline Calibrated Radius", 215f, new ConfigDescription("Exact calibrated native Valheim treeline H in metres. In ManualCalibrated mode this value is authoritative and no legacy offset, fallback, exclusion distance, object distance, or camera distance can change it.", (AcceptableValueBase)(object)new AcceptableValueRange(100f, 1500f), Array.Empty())); _nativeTreelineSeamOverlap = ((BaseUnityPlugin)this).Config.Bind("Native Treeline", "Native Treeline Seam Overlap", 16f, new ConfigDescription("O: a small deterministic blend band subtracted from H. With H=215m and O=16m, detailed cards may begin at 199m so the last native trees and first cards overlap instead of leaving a visible Black Forest gap.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 48f), Array.Empty())); _nativeTreelineHandoffOffset = ((BaseUnityPlugin)this).Config.Bind("Native Treeline", "Native Treeline Handoff Offset", 0f, new ConfigDescription("Legacy compatibility setting. Ignored when Native Treeline Mode = ManualCalibrated so a saved H remains exact. It may adjust only AutoDetect/DefaultFallback experiments.", (AcceptableValueBase)(object)new AcceptableValueRange(-100f, 300f), Array.Empty())); _nativeTreelineBoundaryChunkSize = ((BaseUnityPlugin)this).Config.Bind("Native Treeline", "Native Treeline Boundary Chunk Size", 16f, new ConfigDescription("Size (metres) of New Horizons visibility chunks within the boundary band (effective inner boundary through H+128m). Smaller than the normal far chunk size so a whole chunk is never hidden just because one card inside it crosses the inner boundary.", (AcceptableValueBase)(object)new AcceptableValueRange(8f, 32f), Array.Empty())); _normalForestChunkSize = ((BaseUnityPlugin)this).Config.Bind("Native Treeline", "Normal Forest Chunk Size", 64f, new ConfigDescription("World-space size of normal fixed renderer sub-chunks outside the handoff band. Standard release value is 64m.", (AcceptableValueBase)(object)new AcceptableValueRange(32f, 128f), Array.Empty())); _canopyHandoffOffset = ((BaseUnityPlugin)this).Config.Bind("Native Treeline", "Canopy Handoff Offset", 1300f, new ConfigDescription("Metres added only to EffectiveTreeCardStart for broad canopy/forest-mass cards. Detailed individual tree cards still begin at TreeStart. The release default deliberately keeps canopy beyond the close and near rings so atlas masses cannot appear as giant rectangular walls near the player.", (AcceptableValueBase)(object)new AcceptableValueRange(300f, 3000f), Array.Empty())); _enforceStrictCalibratedTreeline = ((BaseUnityPlugin)this).Config.Bind("Native Treeline", "Enforce Strict Calibrated Treeline", true, "When true, TreeStart = max(0, H - O) is the exact minimum visible edge. The configured seam overlap is honoured, but no card may render closer than TreeStart."); _nativeTreelineSeamFadeWidth = ((BaseUnityPlugin)this).Config.Bind("Native Treeline", "Native Treeline Seam Fade Width", 8f, new ConfigDescription("Reserved for a future material-level alpha fade at the handoff seam. NOT implemented as a shader-level fade this pass (would require a new vertex-colour channel and shader change) -- see IMPLEMENTATION_NOTES_v4.6.0.md. Currently informational only; the boundary itself is always a hard geometric edge at H (or H-O if strict enforcement is off).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 32f), Array.Empty())); _nativeTreelineSeamTolerance = ((BaseUnityPlugin)this).Config.Bind("Native Treeline", "Native Treeline Seam Tolerance", 6f, new ConfigDescription("Diagnostic-only measurement tolerance in metres. It never changes TreeStart or generation.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 16f), Array.Empty())); _enableHandoffFill = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Handoff Fill", "Enable Guaranteed Handoff Fill", true, "When true, a deterministic fixed-world-space coverage pass runs across the band from H to H + Handoff Fill Band Width, biasing the ordinary candidate acceptance roll toward acceptance so the band does not depend on chance alone. Every forced candidate still passes the same strict grounding as an ordinary card -- this never places a floating tree."); _handoffFillBandWidth = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Handoff Fill", "Handoff Fill Band Width", 450f, new ConfigDescription("Width in metres of the deterministic coverage-first band, measured outward from TreeStart. The wider band covers Black Forest shorelines seen from boats and elevated viewpoints.", (AcceptableValueBase)(object)new AcceptableValueRange(64f, 800f), Array.Empty())); _handoffFillMinimumCoverage = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Handoff Fill", "Handoff Fill Minimum Coverage", 0.95f, new ConfigDescription("Minimum spatial coverage target across valid forest land in the close handoff band.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _handoffFillCandidateSpacing = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Handoff Fill", "Handoff Fill Candidate Spacing", 10f, new ConfigDescription("Absolute deterministic world-grid spacing used by handoff and primary coverage. Ten metres is the dense release default; strict grounding and water safety still apply.", (AcceptableValueBase)(object)new AcceptableValueRange(6f, 40f), Array.Empty())); _handoffFillMaximumGap = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Handoff Fill", "Handoff Fill Maximum Valid-Land Gap", 16f, new ConfigDescription("Maximum accepted-card-centre gap on valid close forest land before diagnostics report a handoff violation.", (AcceptableValueBase)(object)new AcceptableValueRange(8f, 64f), Array.Empty())); _handoffFillUsesBiomeDensity = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Handoff Fill", "Handoff Fill Uses Biome Density", true, "When true, the forced-coverage strength within the band still varies by biome (Black Forest strongest, Plains sparsest) instead of forcing identical density everywhere."); _handoffFillRequiresValidForestLand = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Handoff Fill", "Handoff Fill Requires Valid Forest Land", true, "When true, the handoff-fill pass never forces a candidate onto open ocean, unsupported water, or (for swamp candidates) land that resampled away from actual swamp -- it is rejected/skipped there exactly like an ordinary candidate, never forced to float."); _enableContinuousForestCoverage = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Enable Continuous Forest Coverage", true, "Builds one deterministic primary forest pass across every requested tile containing valid land before optional reinforcement. This is the release fix for large empty land patches between dense card clumps."); _continuousMeadowsCoverage = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Meadows Continuous Coverage", 1f, new ConfigDescription("Minimum valid-land coverage target for Meadows forest land, enforced by the guaranteed nearest-neighbour gap check (v4.6.11).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _continuousBlackForestCoverage = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Black Forest Continuous Coverage", 1f, new ConfigDescription("Minimum valid-land coverage target for Black Forest, the strongest of any biome and backed by a dedicated second recovery pass (v4.6.11).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _continuousSwampCoverage = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Swamp Continuous Coverage", 0.9f, new ConfigDescription("Minimum valid-land coverage target on supported final-position swamp land only.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _continuousMountainCoverage = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Mountain Continuous Coverage", 0.9f, new ConfigDescription("Minimum valid-land coverage target on valid mountain tree land.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _continuousPlainsCoverage = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Plains Continuous Coverage", 0.2f, new ConfigDescription("Minimum valid-land coverage target for Plains. Plains remains the least dense ordinary biome.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _continuousMistlandsCoverage = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Mistlands Continuous Coverage", 0.7f, new ConfigDescription("Moderate primary-grid occupancy for Mistlands.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _continuousAshlandsCoverage = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Ashlands Continuous Coverage", 0.18f, new ConfigDescription("Restrained primary-grid occupancy for Ashlands.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _continuousDeepNorthCoverage = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Deep North Continuous Coverage", 0.5f, new ConfigDescription("Primary-grid occupancy for Deep North.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _continuousNearGridRetention = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Near Grid Retention", 1f, new ConfigDescription("Fraction of the 10m candidate grid retained in the handoff and near rings during primary coverage.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 1f), Array.Empty())); _continuousMidGridRetention = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Mid Grid Retention", 1f, new ConfigDescription("Fraction of the 10m candidate grid retained in the mid-distance ring during primary coverage.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 1f), Array.Empty())); _continuousFarGridRetention = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Far Grid Retention", 0.85f, new ConfigDescription("Fraction of the 10m candidate grid retained in the far ring during primary coverage.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 1f), Array.Empty())); _continuousHorizonGridRetention = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Horizon Grid Retention", 0.7f, new ConfigDescription("Fraction of the 10m candidate grid retained in the horizon ring during primary coverage.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 1f), Array.Empty())); _coverageHandoffMaximumGap = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Handoff Ring Maximum Coverage Gap", 18f, new ConfigDescription("Maximum distance from any valid-land point to the nearest accepted primary card in the Handoff ring, enforced by a real spatial nearest-neighbour check (v4.6.11).", (AcceptableValueBase)(object)new AcceptableValueRange(6f, 60f), Array.Empty())); _coverageNearMaximumGap = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Near Ring Maximum Coverage Gap", 22f, new ConfigDescription("Maximum nearest accepted detailed-card gap on valid Near-ring land.", (AcceptableValueBase)(object)new AcceptableValueRange(6f, 90f), Array.Empty())); _coverageMidMaximumGap = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Mid Ring Maximum Coverage Gap", 30f, new ConfigDescription("Maximum nearest accepted detailed-card gap on valid Mid-ring land.", (AcceptableValueBase)(object)new AcceptableValueRange(8f, 150f), Array.Empty())); _coverageFarMaximumGap = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Far Ring Maximum Coverage Gap", 42f, new ConfigDescription("Maximum nearest accepted detailed-card gap on valid Far-ring land.", (AcceptableValueBase)(object)new AcceptableValueRange(8f, 260f), Array.Empty())); _coverageHorizonMaximumGap = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Horizon Ring Maximum Coverage Gap", 60f, new ConfigDescription("Maximum nearest accepted detailed-card gap on valid Horizon-ring land.", (AcceptableValueBase)(object)new AcceptableValueRange(8f, 400f), Array.Empty())); _coverageRepairRecoveryRadius = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Coverage Repair Recovery Radius", 48f, new ConfigDescription("Maximum same-biome recovery search radius used when retrying an unresolved coverage hole.", (AcceptableValueBase)(object)new AcceptableValueRange(8f, 96f), Array.Empty())); _coverageRepairMaxRetries = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Coverage Repair Max Retries", 3, new ConfigDescription("Maximum number of repair attempts for an unresolved coverage hole before it is dropped as exhausted. Black Forest holes receive double this.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 8), Array.Empty())); _coverageRepairJobsPerFrame = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Coverage Repair Jobs Per Frame", 4, new ConfigDescription("Maximum number of repair queue entries processed per frame, keeping repair work incremental inside the existing frame budget.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 16), Array.Empty())); _enableCoastalLandRecovery = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Enable Coastal Land Recovery", true, "When a non-swamp card fails near a shoreline, search nearby deterministic positions in the same biome family and rerun every strict root, biome and water check."); _coastalLandRecoveryRadius = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Coastal Land Recovery Radius", 48f, new ConfigDescription("Maximum deterministic search radius in metres for a nearby same-biome grounded tree position.", (AcceptableValueBase)(object)new AcceptableValueRange(8f, 96f), Array.Empty())); _coastalLandRecoveryAttempts = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Coastal Land Recovery Attempts", 36, new ConfigDescription("Number of deterministic spiral samples used when recovering a rejected coastal card.", (AcceptableValueBase)(object)new AcceptableValueRange(4, 96), Array.Empty())); _blackForestNearMinimumSubclusters = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Black Forest Near Minimum Subclusters", 5, new ConfigDescription("Minimum detailed tree attempts per accepted candidate cell in the Handoff and Near rings of Black Forest.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 6), Array.Empty())); _meadowsNearMinimumSubclusters = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Meadows Near Minimum Subclusters", 2, new ConfigDescription("Minimum detailed tree attempts per accepted candidate cell in the Handoff and Near rings of Meadows.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 5), Array.Empty())); _allowDetailedTreeFoliageOverhangAtCoast = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Allow Detailed Tree Foliage Overhang At Coast", true, "Allows transparent foliage pixels of detailed Meadows and Black Forest cards to extend over the shoreline while the central trunk/root safety footprint remains on supported dry land. Canopy and proxy masses keep full-width water checks."); _coastalDetailedTreeWaterSafetyWidth = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Coastal Detailed Tree Water Safety Width", 3.5f, new ConfigDescription("Width in metres of the central dry-land safety footprint used for detailed coastal tree cards.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 8f), Array.Empty())); _coastalDetailedTreeNearWaterRejectRadius = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Coastal Detailed Tree Near Water Reject Radius", 2.5f, new ConfigDescription("Nearby-water probe radius for detailed coastal tree trunks. Broad canopy/proxy masses retain the generic non-swamp exclusion radius.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 12f), Array.Empty())); _coastalDetailedTreeMinimumAboveWater = ((BaseUnityPlugin)this).Config.Bind("Continuous Forest Coverage", "Coastal Detailed Tree Minimum Above Water", 0.2f, new ConfigDescription("Minimum trunk/root terrain clearance above water for detailed coastal Meadows and Black Forest cards.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 2f), Array.Empty())); _coverageCellsPerResumableStep = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Coverage Cells Per Resumable Step", 24, new ConfigDescription("Maximum valid-land coverage cells audited before yielding. Pressure mode reduces this to eight.", (AcceptableValueBase)(object)new AcceptableValueRange(4, 128), Array.Empty())); _maximumActiveCoverageAuditJobs = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Maximum Active Coverage Audit Jobs", 2, new ConfigDescription("Maximum admitted resumable coverage sectors. Remaining desired sectors stay as lightweight keys.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 8), Array.Empty())); _maximumCoverageRepairJobsAdmittedPerFrame = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Maximum Coverage Repair Jobs Admitted Per Frame", 1, new ConfigDescription("Maximum new repair jobs admitted from audited sectors per frame.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 8), Array.Empty())); _maximumCoverageRepairCardsCommittedPerFrame = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Maximum Coverage Repair Cards Committed Per Frame", 1, new ConfigDescription("Maximum accepted repair cards committed in one frame.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); _maximumCoverageSectorStarvationSeconds = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Maximum Coverage Sector Starvation Seconds", 2f, new ConfigDescription("Maximum time a desired coverage sector may wait without one bounded audit step.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 10f), Array.Empty())); _coastalDryLandSearchRadius = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Coastal Dry-Land Search Radius", 96f, new ConfigDescription("Repair-only deterministic inland search radius for Meadows and Black Forest.", (AcceptableValueBase)(object)new AcceptableValueRange(8f, 192f), Array.Empty())); _coastalSearchMaximumAttempts = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Coastal Search Maximum Attempts", 32, new ConfigDescription("Total deterministic repair-only coastal attempts retained across frames.", (AcceptableValueBase)(object)new AcceptableValueRange(4, 96), Array.Empty())); _coastalSearchAttemptsPerResumableStep = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Coastal Search Attempts Per Resumable Step", 4, new ConfigDescription("Coastal recovery attempts processed before yielding. Pressure mode reduces this to one.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 16), Array.Empty())); _coastalSearchAngularSamples = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Coastal Search Angular Samples", 16, new ConfigDescription("Deterministic angular directions used by repair-only inland recovery.", (AcceptableValueBase)(object)new AcceptableValueRange(4, 32), Array.Empty())); _treeCardDensityPreset = ((BaseUnityPlugin)this).Config.Bind("Tree Card Density", "Tree Card Density Preset", TreeCardDensityPreset.Custom, "Named tree-density profile. Existing CFG values remain Custom until the user explicitly selects a named profile."); _preserveExistingManualTreeCardValues = ((BaseUnityPlugin)this).Config.Bind("Tree Card Density", "Preserve Existing Manual Tree Card Values", true, "Preserve manual tree-card values and classify them as Custom instead of replacing them on startup."); _autoMatchTreeDensityToQualityPreset = ((BaseUnityPlugin)this).Config.Bind("Tree Card Density", "Auto Match Tree Density To Quality Preset", false, "When false, Quality Preset controls range and capacity only."); _globalDistributedTreeDensity = ((BaseUnityPlugin)this).Config.Bind("Tree Card Density", "Global Distributed Tree Density", 1.65f, new ConfigDescription("Global deterministic reinforcement density.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 4f), Array.Empty())); _blackForestDistributedDensity = ((BaseUnityPlugin)this).Config.Bind("Tree Card Density", "Black Forest Distributed Density", 2f, new ConfigDescription("Black Forest reinforcement multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 4f), Array.Empty())); _meadowsDistributedDensity = ((BaseUnityPlugin)this).Config.Bind("Tree Card Density", "Meadows Distributed Density", 1.3f, new ConfigDescription("Meadows reinforcement multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 4f), Array.Empty())); _swampDistributedDensity = ((BaseUnityPlugin)this).Config.Bind("Tree Card Density", "Swamp Distributed Density", 1f, new ConfigDescription("Swamp compatibility multiplier; unchanged by the golden High profile.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 4f), Array.Empty())); _mountainDistributedDensity = ((BaseUnityPlugin)this).Config.Bind("Tree Card Density", "Mountain Distributed Density", 1.15f, new ConfigDescription("Mountain reinforcement multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 4f), Array.Empty())); _plainsDistributedDensity = ((BaseUnityPlugin)this).Config.Bind("Tree Card Density", "Plains Distributed Density", 0.25f, new ConfigDescription("Plains reinforcement multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 4f), Array.Empty())); _newHorizonsExtensionDistance = ((BaseUnityPlugin)this).Config.Bind("Tree Render Distance", "New Horizons Extension Distance", 4000f, new ConfigDescription("E: additional forest distance beyond H, never an absolute player radius. FinalOuterRange = min(H + E, valid provider/world maximum).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 30000f), Array.Empty())); _enableFarTerrain = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Enable Far Terrain Underlay", true, "Draws the visual-only terrain underlay beyond the native Valheim/Render Limits envelope."); _innerTerrainDistance = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Inner Terrain Distance", 1250f, new ConfigDescription("Far terrain mesh leaves this hole around the player. Real Valheim terrain owns the close world.", (AcceptableValueBase)(object)new AcceptableValueRange(300f, 4000f), Array.Empty())); _farTerrainViewDistance = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Far Terrain View Distance", 5200f, new ConfigDescription("Custom preset maximum range for lightweight far terrain. Presets calculate this from native tree range and the active world/provider boundary.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 30000f), Array.Empty())); _farTerrainTileSize = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Far Terrain Tile Size", 700f, new ConfigDescription("Custom preset world metres per far terrain tile.", (AcceptableValueBase)(object)new AcceptableValueRange(500f, 2500f), Array.Empty())); _farTerrainMeshResolution = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Mesh Resolution", 26, new ConfigDescription("Custom preset quads per far terrain tile edge.", (AcceptableValueBase)(object)new AcceptableValueRange(8, 64), Array.Empty())); _farForestStartDistance = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Far Forest Start Distance", 0f, new ConfigDescription("Legacy compatibility setting; ignored for every tree/card start. Far forest routing always uses EffectiveTreeCardStart().", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 12000f), Array.Empty())); _farForestEndDistance = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Far Forest End Distance", 5200f, new ConfigDescription("Distance where far terrain forest tint reaches full strength (practical 1200-16000).", (AcceptableValueBase)(object)new AcceptableValueRange(1200f, 16000f), Array.Empty())); _forestTerrainTintStrength = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Forest Terrain Tint Strength", 0.8f, new ConfigDescription("How strongly forest-density areas are blended toward the forest tint.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _forestTerrainTintColour = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Forest Terrain Tint Colour", "0.14,0.23,0.17", "RGB 0..1 tint applied to forested far-terrain areas."); _terrainDistanceTintStrength = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Distance Tint Strength", 1.1f, new ConfigDescription("How strongly forest tint grows between Far Forest Start Distance and Far Forest End Distance.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1.5f), Array.Empty())); _enableHorizonClarity = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Enable Horizon Clarity", true, "Master switch. Adds contrast/darkness to New Horizons' OWN distant terrain colours and card materials so distant land/forest reads clearly instead of washing into pale fog. Does NOT change Valheim's global fog."); _reduceHorizonHaze = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Reduce Horizon Haze", true, "When on, the clarity contrast/darkness is applied. When off, terrain/cards render at their plain colours."); _horizonHazeStrength = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Horizon Haze Strength", 0.65f, new ConfigDescription("Overall clarity intensity multiplier applied to both terrain and forest clarity amounts.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _terrainDistanceFadeStrength = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Terrain Distance Fade Strength", 0.75f, new ConfigDescription("How strongly terrain clarity ramps up with distance. Higher = distant terrain keeps more definition.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _forestDistanceFadeStrength = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Forest Distance Fade Strength", 0.65f, new ConfigDescription("How strongly forest card clarity is applied. Higher = distant forest cards read darker/clearer against fog.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _farTerrainContrast = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Far Terrain Contrast", 1.38f, new ConfigDescription("Per-pixel contrast target for distant terrain colours. 1 = none.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 2.5f), Array.Empty())); _farForestContrast = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Far Forest Contrast", 1.5f, new ConfigDescription("Contrast target for distant forest tint on terrain. 1 = none.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 2.5f), Array.Empty())); _farForestDarkness = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Far Forest Darkness", 0.74f, new ConfigDescription("Darkness applied to forest card materials so they survive fog washing. 1 = unchanged; lower = darker/clearer.", (AcceptableValueBase)(object)new AcceptableValueRange(0.4f, 1f), Array.Empty())); _farTerrainDarkness = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Far Terrain Darkness", 0.88f, new ConfigDescription("Darkness applied to distant terrain colours. 1 = unchanged; lower = darker/clearer.", (AcceptableValueBase)(object)new AcceptableValueRange(0.4f, 1.2f), Array.Empty())); _farTreeAlpha = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Far Tree Alpha", 1f, new ConfigDescription("Tree card material alpha. 1 = solid. Effect depends on the card shader (cutout shaders may ignore alpha).", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 1f), Array.Empty())); _farCanopyAlpha = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Far Canopy Alpha", 0.97f, new ConfigDescription("Canopy card material alpha. Slightly under 1 softens distant canopy.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 1f), Array.Empty())); _preserveWeatherFog = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Preserve Weather Fog", true, "Kept true: New Horizons never removes Valheim's fog. Weather still sets the mood; clarity only helps the mod's own meshes read through it."); _weatherFogInfluence = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Weather Fog Influence", 0.55f, new ConfigDescription("How strongly the weather visibility boosts below modulate clarity. 0 = ignore weather; 1 = full weather influence.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _clearWeatherVisibilityBoost = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Clear Weather Visibility Boost", 1.35f, new ConfigDescription("Clarity multiplier in clear weather (>1 = distant forest/terrain pops more on clear days).", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 2f), Array.Empty())); _mistWeatherVisibilityBoost = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Mist Weather Visibility Boost", 0.85f, new ConfigDescription("Clarity multiplier in mist/fog (<1 keeps mist atmospheric).", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 1.5f), Array.Empty())); _stormWeatherVisibilityBoost = ((BaseUnityPlugin)this).Config.Bind("Horizon Clarity", "Storm Weather Visibility Boost", 0.75f, new ConfigDescription("Clarity multiplier in thunderstorm/storm (<1 keeps storms dark and enclosed).", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 1.5f), Array.Empty())); _terrainSlopeShadingStrength = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Baked Slope Shading Strength", 0.24f, new ConfigDescription("Subtle build-time terrain shading. Adds depth to ridges and bare rock without adding geometry.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.6f), Array.Empty())); _useBetterContinentsExactSampler = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Use Better Continents Exact Sampler", true, "Required for Donegal custom-map mode. If disabled, BetterContinentsCustomMap provider fails closed rather than using direct heightmap height."); _verticalOffset = ((BaseUnityPlugin)this).Config.Bind("Terrain", "Vertical Offset", -0.25f, new ConfigDescription("Small offset applied after provider ground height. Keep near zero.", (AcceptableValueBase)(object)new AcceptableValueRange(-5f, 2f), Array.Empty())); _forestContinuityEnabled = ((BaseUnityPlugin)this).Config.Bind("Forest", "Enabled", true, "Enables fixed-world low-poly forest masses, transition cards and distant canopy/treeline silhouettes."); _continuityStartDistance = ((BaseUnityPlugin)this).Config.Bind("Forest", "Continuity Start Distance", 0f, new ConfigDescription("Legacy compatibility setting; ignored. ContinuityStart is always EffectiveTreeCardStart().", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1200f), Array.Empty())); _decoupleForestStartFromTerrainExclusion = ((BaseUnityPlugin)this).Config.Bind("Forest", "Decouple Forest Start From Terrain Exclusion", true, "Legacy compatibility switch; tree/card starts are now always decoupled from terrain exclusion."); _minimumForestStartDistance = ((BaseUnityPlugin)this).Config.Bind("Forest", "Minimum Forest Start Distance", 0f, new ConfigDescription("Legacy compatibility setting; ignored. No 500m/550m or other minimum start floor is active.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1200f), Array.Empty())); _forestExclusionMarginScale = ((BaseUnityPlugin)this).Config.Bind("Forest", "Forest Exclusion Margin Scale", 0f, new ConfigDescription("Legacy compatibility setting; ignored by the authoritative final visible-edge boundary.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _treeCardEndDistance = ((BaseUnityPlugin)this).Config.Bind("Forest", "Tree Card End Distance", 1600f, new ConfigDescription("Custom preset distance where individual tree-card clusters give way to canopy. Wide range for horizon forests (practical 1000-14000).", (AcceptableValueBase)(object)new AcceptableValueRange(900f, 14000f), Array.Empty())); _canopyStartDistance = ((BaseUnityPlugin)this).Config.Bind("Forest", "Canopy Start Distance", 225f, new ConfigDescription("Legacy compatibility setting; ignored. CanopyStart is EffectiveTreeCardStart + Canopy Handoff Offset.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 8000f), Array.Empty())); _continuityEndDistance = ((BaseUnityPlugin)this).Config.Bind("Forest", "Continuity End Distance", 4600f, "Custom preset metres from the player where canopy masses fade out."); _continuityTileSize = ((BaseUnityPlugin)this).Config.Bind("Forest", "Continuity Tile Size", 384f, new ConfigDescription("World metres per resumable forest work tile. v4.6.9 lowers the common default from 512m to 384m so one dense tile performs about 44% less candidate/grounding work, reducing single-frame hitches without changing local density or preset range.", (AcceptableValueBase)(object)new AcceptableValueRange(192f, 512f), Array.Empty())); _continuityRebuildDistance = ((BaseUnityPlugin)this).Config.Bind("Forest", "Continuity Rebuild Distance", 128f, new ConfigDescription("Rebuilds local forest/terrain rings after travelling this far.", (AcceptableValueBase)(object)new AcceptableValueRange(64f, 512f), Array.Empty())); _nearCullHysteresis = ((BaseUnityPlugin)this).Config.Bind("Native Treeline", "Near Cull Hysteresis", 4f, new ConfigDescription("Re-enable hysteresis only. It never increases initial generation distance.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 24f), Array.Empty())); _clusterCellSize = ((BaseUnityPlugin)this).Config.Bind("Forest", "Cluster Cell Size", 18f, new ConfigDescription("Shared ordinary local forest spacing for every preset. Handoff and primary coverage use their separate absolute 10m candidate grid.", (AcceptableValueBase)(object)new AcceptableValueRange(12f, 300f), Array.Empty())); _forestDensityThreshold = ((BaseUnityPlugin)this).Config.Bind("Forest", "Forest Density Threshold", 0f, new ConfigDescription("Provider forest density required before a cell can receive visual forest.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.95f), Array.Empty())); _forestDensityMultiplier = ((BaseUnityPlugin)this).Config.Bind("Forest", "Forest Density Multiplier", 13.036f, new ConfigDescription("Multiplies forest density before thresholding. Golden High uses 13.036 exactly.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 25f), Array.Empty())); _slopeRejectionThreshold = ((BaseUnityPlugin)this).Config.Bind("Forest", "Slope Rejection Threshold", 26f, new ConfigDescription("Soft maximum forest slope in degrees.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 60f), Array.Empty())); _hardSlopeRejectionThreshold = ((BaseUnityPlugin)this).Config.Bind("Forest", "Hard Reject Slope", 52.366f, new ConfigDescription("Hard maximum forest slope in degrees.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 75f), Array.Empty())); _maximumClustersPerTile = ((BaseUnityPlugin)this).Config.Bind("Forest", "Maximum Clusters Per Tile", 6799, new ConfigDescription("Hard cap for emitted clusters per local forest tile. Golden High uses 6799.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 12000), Array.Empty())); _maxTreeCardPlanesPerTile = ((BaseUnityPlugin)this).Config.Bind("Forest", "Maximum Tree Card Planes Per Tile", 10945, new ConfigDescription("Tree-card plane cap per forest tile. Golden High uses 10945.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 20000), Array.Empty())); _maxCanopyPlanesPerTile = ((BaseUnityPlugin)this).Config.Bind("Forest", "Maximum Canopy Planes Per Tile", 9906, new ConfigDescription("Golden canopy-card plane capacity per forest tile. This is a capacity ceiling, not a density multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 12000), Array.Empty())); _slopeSampleRadius = ((BaseUnityPlugin)this).Config.Bind("Forest", "Slope Sample Radius", 8f, new ConfigDescription("Metres around each candidate used to compute slope from provider heights.", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 32f), Array.Empty())); _extendMainCameraFarClip = ((BaseUnityPlugin)this).Config.Bind("Camera", "Extend Main Camera Far Clip", true, "Raises the active world camera far clip so the far ring can render."); _mainCameraFarClip = ((BaseUnityPlugin)this).Config.Bind("Camera", "Main Camera Far Clip", 20000f, new ConfigDescription("World camera far clip in metres.", (AcceptableValueBase)(object)new AcceptableValueRange(2500f, 30000f), Array.Empty())); _tilesBuiltPerFrame = ((BaseUnityPlugin)this).Config.Bind("Performance", "Tiles Built Per Frame", 5, new ConfigDescription("Terrain/forest mesh tiles built per frame. Higher populates faster (practical 1-16).", (AcceptableValueBase)(object)new AcceptableValueRange(1, 16), Array.Empty())); _cullBehindCamera = ((BaseUnityPlugin)this).Config.Bind("Performance", "Cull Far Tiles Behind Camera", false, "Optional broad visibility culling. Presets keep this off so range is not hidden behind the camera."); _behindCameraDot = ((BaseUnityPlugin)this).Config.Bind("Performance", "Behind Camera Dot", -0.35f, new ConfigDescription("Only used when behind-camera culling is enabled.", (AcceptableValueBase)(object)new AcceptableValueRange(-1f, 0.5f), Array.Empty())); _maxTerrainTiles = ((BaseUnityPlugin)this).Config.Bind("Performance", "Maximum Terrain Tiles", 450, new ConfigDescription("Custom preset terrain tile cap. Presets use runtime profile budgets.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 800), Array.Empty())); _maxForestTiles = ((BaseUnityPlugin)this).Config.Bind("Performance", "Maximum Forest Tiles", 2200, new ConfigDescription("Custom preset forest tile cap. Standard presets use the exact release capacity table.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 5000), Array.Empty())); _panicTileCeiling = ((BaseUnityPlugin)this).Config.Bind("Performance", "Panic Tile Ceiling", 5000, new ConfigDescription("Absolute terrain-plus-forest request safety ceiling.", (AcceptableValueBase)(object)new AcceptableValueRange(200, 8000), Array.Empty())); _globalTreeCardPlaneBudget = ((BaseUnityPlugin)this).Config.Bind("Performance", "Global Tree Card Plane Budget", 340000, new ConfigDescription("Custom preset global active tree-plane cap.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 500000), Array.Empty())); _globalCanopyPlaneBudget = ((BaseUnityPlugin)this).Config.Bind("Performance", "Global Canopy Plane Budget", 255000, new ConfigDescription("Custom preset global active canopy-plane cap.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 400000), Array.Empty())); _enableRingBudgetReservation = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Enable Ring Budget Reservation", true, "When true, each distance ring is guaranteed a minimum share of the global tree/canopy plane budget, regardless of build order. When false, reverts to a single shared pool (the pre-v4.6.2 behaviour, which starves whichever rings build last)."); _handoffMinimumTreeBudgetShare = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Handoff Minimum Tree Budget Share", 0.25f, new ConfigDescription("Minimum fraction of the global tree-card plane budget reserved for TreeStart through TreeStart+350m.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _nearMinimumTreeBudgetShare = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Near Minimum Tree Budget Share", 0.2f, new ConfigDescription("Minimum fraction of the global tree-card plane budget reserved for the Near ring (H+300m to 1500m).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _midMinimumTreeBudgetShare = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Mid Minimum Tree Budget Share", 0.2f, new ConfigDescription("Minimum fraction of the global tree-card plane budget reserved for the Mid ring (1500m to 4000m).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _farMinimumTreeBudgetShare = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Far Minimum Tree Budget Share", 0.2f, new ConfigDescription("Minimum fraction of the global tree-card plane budget reserved for the Far ring (4000m to 7000m).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _horizonMinimumTreeBudgetShare = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Horizon Minimum Tree Budget Share", 0.15f, new ConfigDescription("Minimum fraction of the global tree-card plane budget reserved for the Horizon ring.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _handoffMinimumCanopyBudgetShare = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Handoff Minimum Canopy Budget Share", 0.25f, new ConfigDescription("Minimum fraction of the global canopy plane budget reserved for the Handoff ring.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _nearMinimumCanopyBudgetShare = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Near Minimum Canopy Budget Share", 0.2f, new ConfigDescription("Minimum fraction of the global canopy plane budget reserved for the Near ring.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _midMinimumCanopyBudgetShare = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Mid Minimum Canopy Budget Share", 0.2f, new ConfigDescription("Minimum fraction of the global canopy plane budget reserved for the Mid ring.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _farMinimumCanopyBudgetShare = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Far Minimum Canopy Budget Share", 0.2f, new ConfigDescription("Minimum fraction of the global canopy plane budget reserved for the Far ring.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _horizonMinimumCanopyBudgetShare = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Horizon Minimum Canopy Budget Share", 0.15f, new ConfigDescription("Minimum fraction of the global canopy plane budget reserved for the Horizon ring.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _allowUnusedRingBudgetRedistribution = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Allow Unused Ring Budget Redistribution", true, "When true, a ring with no pending coverage work (its desired tiles are all already built) releases its unused reserved capacity back to the shared pool for whichever ring is currently building. When false, each ring is hard-capped at exactly its own reserved share, even if other rings are idle."); _nearHandoffMinimumAlpha = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Near Handoff Minimum Alpha", 0.95f, new ConfigDescription("Lower safeguard on card material alpha in the Handoff ring -- lighting/weather may still darken RGB, but alpha (visibility) is never allowed to drop below this.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _midDistanceMinimumAlpha = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Mid Distance Minimum Alpha", 0.85f, new ConfigDescription("Lower safeguard on card material alpha in the Near/Mid rings.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _farDistanceMinimumAlpha = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Far Distance Minimum Alpha", 0.65f, new ConfigDescription("Lower safeguard on card material alpha in the Far ring.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _horizonMinimumAlpha = ((BaseUnityPlugin)this).Config.Bind("Forest Horizon Coverage", "Horizon Minimum Alpha", 0.45f, new ConfigDescription("Lower safeguard on card material alpha in the Horizon ring -- distant cards may fade atmospherically but must never reach fully transparent before the selected outer boundary.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _enableIncrementalForestStreaming = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Enable Incremental Forest Streaming", true, "When true, forest tile rebuilds (movement, slider/preset changes, H/O calibration) compute a desired-vs-existing chunk difference and only add/remove the delta, instead of destroying and rebuilding the whole forest. When false, falls back to the pre-v4.5.7 full clear+requeue behaviour."); _forestGenerationTimeBudgetMs = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Forest Generation Time Budget Ms", 2f, new ConfigDescription("Milliseconds per frame spent building new/changed forest tiles, measured with System.Diagnostics.Stopwatch.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 8f), Array.Empty())); _maxMeshUploadsPerFrame = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Maximum Mesh Uploads Per Frame", 1, new ConfigDescription("Hard upper bound on forest mesh-upload commits per frame.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 8), Array.Empty())); _maxChunkActivationsPerFrame = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Maximum Chunk Activations Per Frame", 1, new ConfigDescription("Hard upper bound on cached visibility-chunk activations per frame.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 32), Array.Empty())); _pauseGenerationAboveFrameTimeMs = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Pause Generation Above Frame Time Ms", 40f, new ConfigDescription("If the previous game frame took longer than this, forest generation is skipped entirely for the current frame. Visibility updates are never paused.", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 200f), Array.Empty())); _slowFrameGenerationBudgetMs = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Slow Frame Generation Budget Ms", 0.5f, new ConfigDescription("Reduced generation time budget used for one frame following a slow frame (see Pause Generation Above Frame Time Ms), instead of skipping generation entirely.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 4f), Array.Empty())); _streamingRecalculateDistance = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Streaming Recalculate Distance", 64f, new ConfigDescription("Distance the player must move before the desired forest chunk set is recomputed. Same role as Continuity Rebuild Distance but documented here for the streaming system.", (AcceptableValueBase)(object)new AcceptableValueRange(16f, 256f), Array.Empty())); _sliderRebuildDebounceSeconds = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Slider Rebuild Debounce Seconds", 0.6f, new ConfigDescription("Seconds of no further E/H/O change before a debounced streaming sync fires. Matches the pre-existing debounce timing.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 2f), Array.Empty())); _forestRetirementTimeBudgetMs = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Forest Retirement Time Budget Ms", 1f, new ConfigDescription("Milliseconds per frame spent destroying retired/evicted forest tiles.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 8f), Array.Empty())); _maxChunkDestructionsPerFrame = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Maximum Chunk Destructions Per Frame", 4, new ConfigDescription("Upper bound on forest tiles actually Destroy()ed per frame, regardless of remaining retirement time budget.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 32), Array.Empty())); _maxForestJobRetries = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Maximum Forest Job Retries", 2, new ConfigDescription("A forest tile build that throws is retried up to this many times before being marked permanently failed and skipped.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 10), Array.Empty())); _maximumCandidateCellsPerTileBuild = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Maximum Candidate Cells Per Tile Build", 900, new ConfigDescription("Total deterministic candidate cells eventually evaluated per tile. This controls final density, not per-frame work.", (AcceptableValueBase)(object)new AcceptableValueRange(64, 5000), Array.Empty())); _candidateEvaluationsPerResumableStep = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Candidate Evaluations Per Resumable Step", 48, new ConfigDescription("Maximum candidate evaluations before yielding to the next frame. Does not reduce the final candidate total.", (AcceptableValueBase)(object)new AcceptableValueRange(8, 256), Array.Empty())); _enableAdaptiveForestGenerationBudget = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Enable Adaptive Forest Generation Budget", true, "Applies an elapsed-time CPU budget to candidate, grounding, coverage, mesh assembly and upload stages without changing final logical card count."); _normalForestGenerationCpuBudgetMs = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Normal Forest Generation CPU Budget Ms", 1f, new ConfigDescription("Normal moving-world generation budget per frame.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 5f), Array.Empty())); _stationaryForestGenerationCpuBudgetMs = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Stationary Forest Generation CPU Budget Ms", 1.5f, new ConfigDescription("Generation budget after the player and frame time remain stable.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 6f), Array.Empty())); _movementPressureForestGenerationCpuBudgetMs = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Movement Pressure Forest Generation CPU Budget Ms", 0.4f, new ConfigDescription("Budget while moving quickly, sailing, turning rapidly, teleporting or under frame pressure.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 2f), Array.Empty())); _startupForestGenerationCpuBudgetMs = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Startup Forest Generation CPU Budget Ms", 0.5f, new ConfigDescription("Budget while startup safe mode is active.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 2f), Array.Empty())); _generationTargetFrameTimeMs = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Target Frame Time Ms", 16.67f, new ConfigDescription("Recent frame-time target for pressure detection.", (AcceptableValueBase)(object)new AcceptableValueRange(8f, 50f), Array.Empty())); _generationBudgetRecoveryDelaySeconds = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Generation Budget Recovery Delay Seconds", 1f, new ConfigDescription("Stable time required before normal/stationary budgets resume.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 10f), Array.Empty())); _terrainGroundSamplesPerResumableStep = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Terrain/Ground Samples Per Resumable Step", 24, new ConfigDescription("Diagnostic and scheduler limit for terrain/provider sampling slices.", (AcceptableValueBase)(object)new AcceptableValueRange(4, 128), Array.Empty())); _footprintValidationsPerResumableStep = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Footprint Validations Per Resumable Step", 12, new ConfigDescription("Diagnostic and scheduler limit for strict footprint-validation slices.", (AcceptableValueBase)(object)new AcceptableValueRange(2, 64), Array.Empty())); _slopeValidationsPerResumableStep = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Slope Validations Per Resumable Step", 16, new ConfigDescription("Diagnostic and scheduler limit for slope-validation slices.", (AcceptableValueBase)(object)new AcceptableValueRange(2, 64), Array.Empty())); _cardsAppendedToMeshPerResumableStep = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Cards Appended To Mesh Per Resumable Step", 48, new ConfigDescription("Maximum logical-card accumulation between candidate iterator yields. Pressure mode reduces this to sixteen.", (AcceptableValueBase)(object)new AcceptableValueRange(8, 256), Array.Empty())); _maximumSimultaneousMeshAssemblyJobs = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Maximum Simultaneous Mesh Assembly Jobs", 2, new ConfigDescription("Maximum retained mesh-assembly continuations.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); _maximumCompletedForestTileCommitsPerFrame = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Maximum Completed Forest Tile Commits Per Frame", 1, new ConfigDescription("Maximum fully assembled forest tiles committed in one frame.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); _repairChunkRebuildCoalescingSeconds = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Repair Chunk Rebuild Coalescing Seconds", 0.3f, new ConfigDescription("Repair buffer coalescing window; repair work never triggers a full active-range rebuild.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _maximumAdmittedForestGenerationJobs = ((BaseUnityPlugin)this).Config.Bind("Generation Hitch Guard", "Maximum Fully Admitted Active Forest-Generation Jobs", 2, new ConfigDescription("Maximum heavyweight generation continuations; all other desired work remains lightweight queue entries.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); _hardCandidateEvaluationCeiling = ((BaseUnityPlugin)this).Config.Bind("Startup Performance Safety", "Hard Candidate Evaluation Ceiling", 900, new ConfigDescription("Legacy compatibility value. It no longer truncates final candidate completion; Candidate Evaluations Per Resumable Step controls generation speed safely.", (AcceptableValueBase)(object)new AcceptableValueRange(48, 5000), Array.Empty())); _maximumForestTileBuildsPerFrameSafetyCap = ((BaseUnityPlugin)this).Config.Bind("Startup Performance Safety", "Maximum Forest Tile Builds Per Frame Safety Cap", 1, new ConfigDescription("Hard safety cap applied after preset/adaptive values. One synchronous tile can still be expensive, so the default prevents High/Ultra profiles from attempting several tiles in one Unity frame.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 2), Array.Empty())); _enableStartupHitchGuard = ((BaseUnityPlugin)this).Config.Bind("Startup Performance Safety", "Enable Startup Hitch Guard", true, "Staggers forest and far-terrain generation after atlas materials become ready, allowing Valheim and other world mods to finish settling instead of releasing the entire initial backlog at once."); _startupInitialDelaySeconds = ((BaseUnityPlugin)this).Config.Bind("Startup Performance Safety", "Startup Initial Delay Seconds", 1.5f, new ConfigDescription("Brief delay after all forest atlas materials become ready before the first New Horizons forest tile is built.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10f), Array.Empty())); _startupSafeModeSeconds = ((BaseUnityPlugin)this).Config.Bind("Startup Performance Safety", "Startup Safe Mode Seconds", 45f, new ConfigDescription("Duration after atlas readiness during which builds are deliberately staggered, optional reinforcement is paused and coverage repair waits for a stable nearby forest base.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 180f), Array.Empty())); _startupForestBuildIntervalFrames = ((BaseUnityPlugin)this).Config.Bind("Startup Performance Safety", "Startup Forest Build Interval Frames", 2, new ConfigDescription("During startup safe mode, permit at most one forest tile build every N eligible forest-processing frames.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 12), Array.Empty())); _startupTerrainBuildIntervalFrames = ((BaseUnityPlugin)this).Config.Bind("Startup Performance Safety", "Startup Terrain Build Interval Frames", 6, new ConfigDescription("During startup safe mode, permit at most one far-terrain tile build every N terrain-processing frames.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 30), Array.Empty())); _runExpensiveDeterministicStartupSelfTest = ((BaseUnityPlugin)this).Config.Bind("Startup Performance Safety", "Run Expensive Deterministic Startup Self-Test", false, "Developer-only test that synchronously builds four complete forest tiles at startup. Disabled by default because it caused a large avoidable world-entry freeze; normal runtime per-tile hash verification remains active."); _coverageRepairTimeBudgetMs = ((BaseUnityPlugin)this).Config.Bind("Startup Performance Safety", "Coverage Repair Time Budget Ms", 0.35f, new ConfigDescription("Stopwatch budget for coverage-repair work per frame. A single repair attempt cannot be pre-empted mid-call, but the budget prevents multiple expensive attempts from stacking in one frame.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 2f), Array.Empty())); _coverageRepairHardJobsPerFrame = ((BaseUnityPlugin)this).Config.Bind("Startup Performance Safety", "Coverage Repair Hard Jobs Per Frame", 1, new ConfigDescription("Absolute cap on coverage-repair jobs attempted in one frame, independent of the older Coverage Repair Jobs Per Frame setting.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); _minimumActiveChunksBeforeCoverageRepair = ((BaseUnityPlugin)this).Config.Bind("Startup Performance Safety", "Minimum Active Chunks Before Coverage Repair", 24, new ConfigDescription("Coverage-hole repair waits until at least this many ordinary forest tiles are active, preventing repair meshes from competing with the first visible handoff/near chunks during world entry.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 256), Array.Empty())); _minimumMovementSyncIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Minimum Movement Sync Interval Seconds", 0.35f, new ConfigDescription("Minimum real time between routine movement-triggered forest/terrain queue syncs. Fast movement crossing the rebuild threshold on consecutive frames coalesces into one sync at this cadence instead of one per frame.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _fastMovementRebuildDistance = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Fast Movement Rebuild Distance", 256f, new ConfigDescription("A single movement at or beyond this distance always syncs immediately, bypassing the minimum sync interval -- prevents a large jump/teleport from being coalesced away.", (AcceptableValueBase)(object)new AcceptableValueRange(128f, 1024f), Array.Empty())); _maximumMovementSyncsPerSecond = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Maximum Movement Syncs Per Second", 3f, new ConfigDescription("Upper bound on movement-triggered queue syncs per second. Combined with Minimum Movement Sync Interval Seconds -- whichever produces the longer interval wins.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 20f), Array.Empty())); _enableForestObjectPooling = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Enable Forest Object Pooling", true, "Retired forest tiles are disabled and held (not destroyed) so a revisit within the retention window and with an unchanged generation signature can be reactivated instantly with zero recomputation and zero new GameObject/mesh allocation. See IMPLEMENTATION_NOTES_v4.5.7.md for the exact scope of what this does and does not pool."); _maxPooledForestChunks = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Maximum Pooled Forest Chunks", 512, new ConfigDescription("Upper bound on retained (disabled but not destroyed) forest tiles.", (AcceptableValueBase)(object)new AcceptableValueRange(16, 4096), Array.Empty())); _maxPooledMeshes = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Maximum Pooled Meshes", 2048, new ConfigDescription("Advisory upper bound on baked meshes held by retained tiles (roughly 5 per tile); used for F8 reporting and as a secondary eviction trigger.", (AcceptableValueBase)(object)new AcceptableValueRange(64, 16384), Array.Empty())); _clearPoolsOnWorldChange = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Clear Pools On World Change", true, "Purges every retained/cached forest tile (rather than trying to reuse any of it) whenever the world/provider identity changes."); _enableForestMemoryCache = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Enable Forest Memory Cache", true, "Alias/companion to Enable Forest Object Pooling in this build -- both are implemented by the same retained-tile cache (see notes). Kept as a separate switch for config compatibility with the spec."); _forestMemoryCacheLimitMb = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Forest Memory Cache Limit MB", 256f, new ConfigDescription("Approximate memory ceiling (estimated from card/vertex counts, not a precise Unity profiler measurement) for retained forest tiles before LRU eviction.", (AcceptableValueBase)(object)new AcceptableValueRange(16f, 2048f), Array.Empty())); _maxCachedForestChunks = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Maximum Cached Forest Chunks", 2048, new ConfigDescription("Hard upper bound on retained forest tiles, independent of the memory estimate.", (AcceptableValueBase)(object)new AcceptableValueRange(16, 8192), Array.Empty())); _cacheRetentionDistance = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Cache Retention Distance", 512f, new ConfigDescription("Retained tiles further than this beyond the current outer boundary are evicted even if the cache is under its size/memory limit.", (AcceptableValueBase)(object)new AcceptableValueRange(64f, 4000f), Array.Empty())); _forestPreloadDistance = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Forest Preload Distance", 192f, new ConfigDescription("Extra distance beyond the visible outer boundary that is still included in the desired chunk set (biased toward the camera-facing direction by the priority queue), so tiles are often ready just before they become visible. Does not change the actual visible outer tree distance.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1000f), Array.Empty())); _forestChunkRetentionDistance = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Forest Chunk Retention Distance", 256f, new ConfigDescription("Distance beyond the desired set (on top of the preload distance) a retired tile is still allowed to sit in the retained cache rather than being queued for destruction.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2000f), Array.Empty())); _forestFarChunkMergeEnabled = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Enable Far Chunk Batching", true, "Groups Far-ring renderer buffers into fixed world chunks. Card positions, biome routing and grounding remain unchanged; only renderer/GameObject count is reduced."); _midForestChunkSize = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Mid Chunk Size", 96f, new ConfigDescription("Renderer chunk size used for the Mid ring. This changes batching only; logical cards, accepted positions and density are unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange(64f, 128f), Array.Empty())); _forestFarChunkSize = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Far Chunk Size", 128f, new ConfigDescription("Renderer chunk size used for the Far ring. Smaller cells improve frustum rejection of dense distant forests.", (AcceptableValueBase)(object)new AcceptableValueRange(64f, 256f), Array.Empty())); _forestFarChunkMergeStart = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Far Chunk Merge Start Beyond H", 2500f, new ConfigDescription("Legacy compatibility threshold. Ring-safe batching now starts from the explicit Far ring.", (AcceptableValueBase)(object)new AcceptableValueRange(512f, 8000f), Array.Empty())); _forestVeryFarChunkMergeEnabled = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Enable Very Far Chunk Batching", true, "Groups Horizon-ring renderer buffers without moving or removing cards."); _forestVeryFarChunkSize = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Very Far Chunk Size", 160f, new ConfigDescription("Renderer chunk size used for the Horizon ring. The hard accepted maximum is 192m.", (AcceptableValueBase)(object)new AcceptableValueRange(128f, 192f), Array.Empty())); _forestVeryFarChunkMergeStart = ((BaseUnityPlugin)this).Config.Bind("Forest Streaming", "Very Far Chunk Merge Start Beyond H", 6000f, new ConfigDescription("Legacy compatibility threshold. Ring-safe batching now uses the explicit Far and Horizon ring classification.", (AcceptableValueBase)(object)new AcceptableValueRange(1500f, 12000f), Array.Empty())); MigrateV4622RendererChunkDefaults(); _minimumTreeMaterialUpdateIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind("Forest Rendering Performance", "Tree Material Update Interval Seconds", 0.25f, new ConfigDescription("Base interval between shared tree material/property-block update passes. The view-facing overload guard may postpone non-essential passes further.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 2f), Array.Empty())); _minimumBrightnessChangeBeforeUpdate = ((BaseUnityPlugin)this).Config.Bind("Forest Rendering Performance", "Minimum Brightness Change Before Update", 0.02f, new ConfigDescription("Minimum material brightness change required before rewriting tree renderer property blocks.", (AcceptableValueBase)(object)new AcceptableValueRange(0.001f, 0.25f), Array.Empty())); _visibilityUpdateIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind("Forest Rendering Performance", "Visibility Update Interval Seconds", 0.1f, new ConfigDescription("Interval between forest visibility/culling updates.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 1f), Array.Empty())); _enableFarSinglePlaneLod = ((BaseUnityPlugin)this).Config.Bind("Far Tree Rendering Performance", "Enable Far Single Plane LOD", true, "Uses one player-reference-facing double-sided plane for eligible Far/Horizon detailed cards while retaining every logical card and its golden budget charge."); _farSinglePlaneLodStartDistance = ((BaseUnityPlugin)this).Config.Bind("Far Tree Rendering Performance", "Far Single Plane LOD Start Distance", 1400f, new ConfigDescription("Minimum distance for Far-ring single-plane visual LOD.", (AcceptableValueBase)(object)new AcceptableValueRange(1000f, 6000f), Array.Empty())); _horizonSinglePlaneLodStartDistance = ((BaseUnityPlugin)this).Config.Bind("Far Tree Rendering Performance", "Horizon Single Plane LOD Start Distance", 2600f, new ConfigDescription("Minimum distance for Horizon-ring single-plane visual LOD.", (AcceptableValueBase)(object)new AcceptableValueRange(1500f, 10000f), Array.Empty())); _enableViewFacingForestOverloadGuard = ((BaseUnityPlugin)this).Config.Bind("View-Facing Forest Overload Guard", "Enable View-Facing Forest Overload Guard", true, "Geometry-only overload guard. It may simplify eligible distant cards and defer non-essential renderer updates, but never changes logical card acceptance, positions, density, coverage or biome composition."); _visibleDetailedTriangleSoftLimit = ((BaseUnityPlugin)this).Config.Bind("View-Facing Forest Overload Guard", "Visible Detailed Triangle Soft Limit", 220000, new ConfigDescription("Visible detailed-tree triangle count that enters Soft guard state.", (AcceptableValueBase)(object)new AcceptableValueRange(10000, 2000000), Array.Empty())); _visibleDetailedTriangleHardLimit = ((BaseUnityPlugin)this).Config.Bind("View-Facing Forest Overload Guard", "Visible Detailed Triangle Hard Limit", 320000, new ConfigDescription("Visible detailed-tree triangle count that enters Hard guard state and permits Mid cards beyond 1200m to use one plane on legitimate rebuild.", (AcceptableValueBase)(object)new AcceptableValueRange(20000, 3000000), Array.Empty())); _visibleTreeRendererSoftLimit = ((BaseUnityPlugin)this).Config.Bind("View-Facing Forest Overload Guard", "Visible Tree Renderer Soft Limit", 450, new ConfigDescription("Visible New Horizons tree renderer count that enters Soft guard state.", (AcceptableValueBase)(object)new AcceptableValueRange(50, 5000), Array.Empty())); _visibleTreeRendererHardLimit = ((BaseUnityPlugin)this).Config.Bind("View-Facing Forest Overload Guard", "Visible Tree Renderer Hard Limit", 650, new ConfigDescription("Visible New Horizons tree renderer count that enters Hard guard state.", (AcceptableValueBase)(object)new AcceptableValueRange(100, 10000), Array.Empty())); _enableAdaptiveHighPresetGovernor = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Enable Adaptive High Preset Governor", true, "Applies only to High, Ultra, Horizon, or a Custom extension of at least 7000m. Dynamically throttles queued build/upload/activation work from measured frame time while preserving all existing primary trees and deterministic placement."); _adaptiveTargetFrameTimeMs = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Target Frame Time Ms", 16.67f, new ConfigDescription("Target frame time used by the adaptive governor (16.67ms is 60 FPS).", (AcceptableValueBase)(object)new AcceptableValueRange(8f, 40f), Array.Empty())); _adaptiveSoftFrameTimeMs = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Soft Frame Time Ms", 22.22f, new ConfigDescription("Above this rolling frame time the governor begins strongly reducing new forest work (22.22ms is 45 FPS).", (AcceptableValueBase)(object)new AcceptableValueRange(10f, 66f), Array.Empty())); _adaptiveHardFrameTimeMs = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Hard Frame Time Ms", 33.33f, new ConfigDescription("At or above this frame time new generation enters a short cooldown (33.33ms is 30 FPS).", (AcceptableValueBase)(object)new AcceptableValueRange(16f, 120f), Array.Empty())); _adaptiveFrameSmoothingSamples = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Frame Smoothing Samples", 45, new ConfigDescription("Equivalent EMA window used for rolling frame-time pressure.", (AcceptableValueBase)(object)new AcceptableValueRange(8, 180), Array.Empty())); _adaptiveRecoveryDelaySeconds = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Recovery Delay Seconds", 2f, new ConfigDescription("Stable time required before workload pressure is allowed to fall again.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 10f), Array.Empty())); _adaptiveRecoveryRatePerSecond = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Recovery Rate Per Second", 0.12f, new ConfigDescription("How slowly the governor restores full workload after performance stabilises. Lower avoids oscillation.", (AcceptableValueBase)(object)new AcceptableValueRange(0.02f, 1f), Array.Empty())); _adaptiveMinimumGenerationBudgetMs = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Minimum Generation Budget Ms", 0.2f, new ConfigDescription("Smallest generation admission budget while under pressure. Existing forest visibility is never disabled.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 2f), Array.Empty())); _adaptiveMinimumMeshUploadsPerFrame = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Minimum Mesh Uploads Per Frame", 1, new ConfigDescription("Minimum forest tile uploads admitted per frame under pressure.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); _adaptiveMinimumChunkActivationsPerFrame = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Minimum Cache Activations Per Frame", 2, new ConfigDescription("Minimum cached tile activations admitted per frame under pressure.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 16), Array.Empty())); _adaptiveHardSpikeCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Hard Spike Cooldown Seconds", 0.35f, new ConfigDescription("Generation pause after a hard frame spike. Visibility and already-built trees continue normally.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _adaptiveMaximumBuildOverrunCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Maximum Build Overrun Cooldown Seconds", 0.5f, new ConfigDescription("Maximum rest period after a single tile exceeds the admitted frame budget.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _adaptiveReinforcementDeferPressure = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Reinforcement Defer Pressure", 0.35f, new ConfigDescription("Above this 0-1 pressure, optional reinforcement jobs wait while primary handoff/near/far coverage remains protected.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _bootstrapPrimaryGenerationBudgetMs = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Bootstrap Primary Generation Budget Ms", 0.75f, new ConfigDescription("Minimum generation time budget granted per frame while bootstrapping (zero visible chunks or starved primary progress), even if the normal hitch/cooldown pause would otherwise skip the frame entirely.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 4f), Array.Empty())); _minimumPrimaryProgressStepsPerFrame = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Minimum Primary Progress Steps Per Frame", 1, new ConfigDescription("Minimum number of primary-coverage tile builds guaranteed to be attempted per frame while bootstrapping.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); _maximumPrimaryStarvationSeconds = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Maximum Primary Starvation Seconds", 1f, new ConfigDescription("If no primary tile has completed for longer than this, bootstrap protection engages regardless of visible chunk count, preventing indefinite starvation under sustained pressure.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 5f), Array.Empty())); _maximumReinforcementStarvationSeconds = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Maximum Reinforcement Starvation Seconds", 1.5f, new ConfigDescription("Maximum delay before one bounded required reinforcement step bypasses pressure deferral.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 10f), Array.Empty())); _minimumReinforcementProgressStepsAfterStarvation = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Minimum Reinforcement Progress Steps After Starvation", 1, new ConfigDescription("Bounded reinforcement steps guaranteed after starvation without synchronously completing a tile.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); _maximumCoverageStarvationSeconds = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Maximum Coverage Starvation Seconds", 1.5f, new ConfigDescription("Maximum delay before one bounded coverage audit or repair step runs.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 10f), Array.Empty())); _minimumCoverageProgressStepsAfterStarvation = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Minimum Coverage Progress Steps After Starvation", 1, new ConfigDescription("Bounded coverage steps guaranteed after starvation.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); _maximumDesiredTileStarvationSeconds = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Maximum Desired Tile Starvation Seconds", 3f, new ConfigDescription("Maximum queue age before a desired tile receives a priority boost; content and ring priority remain unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 15f), Array.Empty())); _bootstrapMeshUploadsPerFrame = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Bootstrap Mesh Uploads Per Frame", 1, new ConfigDescription("Minimum mesh uploads guaranteed per frame while bootstrapping, so pressure cannot indefinitely block the first completed chunks from becoming visible.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); _enablePredictiveStreamingPriority = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Enable Predictive Streaming Priority", true, "Biases queued primary work toward camera direction and actual player/boat movement. It does not cull or remove behind-camera forest."); _predictiveMovementPriorityStrength = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Movement Priority Strength", 5000f, new ConfigDescription("Queue-score bonus for tiles ahead of current movement.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 20000f), Array.Empty())); _predictiveCameraPriorityStrength = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Camera Priority Strength", 3000f, new ConfigDescription("Queue-score bonus for tiles in the current camera direction.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 20000f), Array.Empty())); _adaptiveTerrainBuildIntervalFrames = ((BaseUnityPlugin)this).Config.Bind("Adaptive High Preset Performance", "Terrain Build Interval Frames", 4, new ConfigDescription("Under High+ adaptive mode, forest and far-terrain mesh creation do not run in the same frame. One terrain build turn is allowed after this many forest scheduler frames.", (AcceptableValueBase)(object)new AcceptableValueRange(2, 30), Array.Empty())); _hazeControlMode = ((BaseUnityPlugin)this).Config.Bind("Atmosphere", "Haze Control Mode", HazeControlMode.Auto, "Disabled | Auto | YieldToExternal | ForceHorizonLiftFog. Auto only touches clear/light weather and yields to active external fog mods."); _clearWeatherHazeMultiplier = ((BaseUnityPlugin)this).Config.Bind("Atmosphere", "Clear Weather Haze Multiplier", 0.82f, new ConfigDescription("Multiplier applied only to eligible clear weather fog density.", (AcceptableValueBase)(object)new AcceptableValueRange(0.65f, 1f), Array.Empty())); _lightCloudHazeMultiplier = ((BaseUnityPlugin)this).Config.Bind("Atmosphere", "Light Cloud Haze Multiplier", 0.88f, new ConfigDescription("Softer multiplier for light cloud/twilight environments.", (AcceptableValueBase)(object)new AcceptableValueRange(0.7f, 1f), Array.Empty())); _maximumHazeReduction = ((BaseUnityPlugin)this).Config.Bind("Atmosphere", "Maximum Haze Reduction", 0.28f, new ConfigDescription("Safety limit: 0.28 means fog density can never be reduced by more than 28 percent.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.45f), Array.Empty())); _hazeBlendSpeed = ((BaseUnityPlugin)this).Config.Bind("Atmosphere", "Haze Blend Speed", 2f, new ConfigDescription("How quickly fog density blends toward the clear-weather target. Superseded by [Real Clear Skies] when that is enabled -- see Clear Weather Transition Seconds.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 8f), Array.Empty())); _enableRealClearSkies = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Enable Real Clear Skies", true, "Master switch. When false, falls back to the older, more conservative [Atmosphere] Clear/Light Weather Haze Multiplier behaviour."); _clearSkiesStrength = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Clear Skies Strength", 0.85f, new ConfigDescription("Overall reversible clear-sky blend strength.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _clearSkiesOperatingMode = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Clear Skies Operating Mode", ClearSkiesOperatingMode.NaturalWeatherAndOccasionalEvent, "Disabled: feature off (falls back to legacy [Atmosphere] haze). NaturalWeatherOnly: applies the ordinary clear/light-weather profile. NaturalWeatherAndOccasionalEvent (default): applies that ordinary profile and occasionally switches to the stronger deterministic Crystal Clear profile. PermanentCinematicOverride: keeps the eligible-weather profile fully targeted whenever preservation rules allow it."); _allowOccasionalCrystalClearWeather = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Allow Occasional Crystal Clear Weather", true, "Only relevant when Clear Skies Operating Mode = NaturalWeatherAndOccasionalEvent. When false, that mode behaves like NaturalWeatherOnly (no occasional event, ever)."); _crystalClearChancePerClearDay = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Crystal Clear Weather Chance Per Clear Day", 0.2f, new ConfigDescription("Probability, rolled once per in-game day (deterministically, from world seed + day number -- never per-frame random) the first time that day's weather is clear, that a Crystal Clear event starts.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _crystalClearMinimumDurationMinutes = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Crystal Clear Minimum Duration Minutes", 4f, new ConfigDescription("Minimum real-time duration of a Crystal Clear event once triggered.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 60f), Array.Empty())); _crystalClearMaximumDurationMinutes = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Crystal Clear Maximum Duration Minutes", 12f, new ConfigDescription("Maximum real-time duration of a Crystal Clear event once triggered.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 90f), Array.Empty())); _crystalClearFogMultiplier = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Crystal Clear Fog Multiplier", 0.08f, new ConfigDescription("Native fog-density multiplier during an active Crystal Clear event.", (AcceptableValueBase)(object)new AcceptableValueRange(0.02f, 1f), Array.Empty())); _crystalClearHorizonHazeMultiplier = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Crystal Clear Horizon Haze Multiplier", 0.08f, new ConfigDescription("New Horizons haze multiplier during an active Crystal Clear event.", (AcceptableValueBase)(object)new AcceptableValueRange(0.02f, 1f), Array.Empty())); _crystalClearCloudOpacityMultiplier = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Crystal Clear Cloud Opacity Multiplier", 0.15f, new ConfigDescription("Cloud-opacity multiplier during an active Crystal Clear event.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _crystalClearDistanceTintMultiplier = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Crystal Clear Distance Tint Multiplier", 0.45f, new ConfigDescription("Distant tint-darkness multiplier during an active Crystal Clear event -- stronger than Clear Weather Distance Tint Multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0.15f, 1.5f), Array.Empty())); _clearWeatherFogMultiplier = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Clear Weather Fog Multiplier", 0.2f, new ConfigDescription("Native fog-density multiplier for eligible clear weather modes.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 1f), Array.Empty())); _clearWeatherHorizonHazeMultiplier = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Clear Weather Horizon Haze Multiplier", 0.25f, new ConfigDescription("New Horizons haze multiplier for eligible clear weather modes.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 1f), Array.Empty())); _clearWeatherCloudOpacityMultiplier = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Clear Weather Cloud Opacity Multiplier", 0.45f, new ConfigDescription("Target opacity multiplier for detected cloud renderers at full clear-sky blend. Best-effort: see Cloud Control Status in F8 diagnostics -- not every Valheim build/version is guaranteed to expose a detectable cloud renderer.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _clearWeatherDistanceTintMultiplier = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Clear Weather Distance Tint Multiplier", 0.7f, new ConfigDescription("Multiplier applied to New Horizons' own far-terrain/forest distance tint darkness at full clear-sky blend (lower = less darkening = more readable distant treelines).", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 1.5f), Array.Empty())); _clearSkiesTransitionSeconds = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Clear Skies Transition Seconds", 10f, new ConfigDescription("Seconds to blend from captured original weather values to the selected reversible clear-sky target.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 30f), Array.Empty())); _preserveStormWeather = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Preserve Storm Weather", true, "BAD weather (rain/storm/thunder/snow/blizzard/heavy fog/ash storm) always blends toward zero clear-sky amount when this is true."); _preserveRainAndSnow = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Preserve Rain And Snow", true, "Alias of the rain/snow portion of Preserve Storm Weather, kept as a separate switch for config clarity. Both must be true for full BAD-weather preservation."); _preserveMistlandsMist = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Preserve Mistlands Mist", true, "Player standing in Mistlands blends toward zero clear-sky amount when this is true, regardless of weather-name classification."); _preserveAshlandsAtmosphere = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Preserve Ashlands Atmosphere", true, "Player standing in Ashlands blends toward zero clear-sky amount when this is true."); _preserveDeepNorthAtmosphere = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Preserve Deep North Atmosphere", true, "Player standing in the Deep North blends toward zero clear-sky amount when this is true."); _preserveBossWeather = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Preserve Boss Weather", true, "Boss and boss-adjacent environment names always restore the original atmosphere."); _restoreOriginalWeatherValuesOnDisable = ((BaseUnityPlugin)this).Config.Bind("Real Clear Skies", "Restore Original Weather Values On Disable", true, "Restore native fog/cloud values when Real Clear Skies (or the whole plugin) is disabled or destroyed. Strongly recommended to leave true."); _waterSurfaceMode = ((BaseUnityPlugin)this).Config.Bind("Water", "Water Surface Mode", WaterSurfaceMode.Auto, "Auto | Override | DisableLowlandForest. Auto reads active ZoneSystem water level when available."); _waterSurfaceHeightOverride = ((BaseUnityPlugin)this).Config.Bind("Water", "Water Surface Height Override", 0f, "Only used when Water Surface Mode = Override."); _waterClearance = ((BaseUnityPlugin)this).Config.Bind("Water", "Water Clearance", 3f, new ConfigDescription("Forest candidates at/below water plus this clearance are rejected.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 20f), Array.Empty())); _shoreSampleRadius = ((BaseUnityPlugin)this).Config.Bind("Water", "Shore Sample Radius", 12f, new ConfigDescription("Nearby provider samples used for conservative shore rejection.", (AcceptableValueBase)(object)new AcceptableValueRange(4f, 80f), Array.Empty())); _reloadKey = ((BaseUnityPlugin)this).Config.Bind("Controls", "F6 Reload Key", (KeyCode)287, "Reload provider data, atlas materials, config values, and rebuild all visual meshes. Note: a replaced DLL still requires a full game restart."); _alternateReloadKey = ((BaseUnityPlugin)this).Config.Bind("Controls", "Alternate Reload Key", (KeyCode)278, "Second reload key in case F6 is swallowed by the keyboard/game/overlay. Default Home."); _enableHardcodedReloadFallbacks = ((BaseUnityPlugin)this).Config.Bind("Controls", "Enable Hardcoded Reload Fallbacks", true, "When enabled, Home and Ctrl+R also trigger reload even if the main F6 key is not detected."); if (_reloadKey != null && (int)_reloadKey.Value == 286) { _reloadKey.Value = (KeyCode)287; ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Migrated legacy primary reload key binding to F6."); } if (_alternateReloadKey != null && (int)_alternateReloadKey.Value == 286) { _alternateReloadKey.Value = (KeyCode)278; ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Migrated legacy alternate reload key binding to Home."); } _enableCalibrationMode = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Enable Calibration Mode", false, "Safety gate: the calibration toggle key below does nothing unless this is true. Diagnostic/setup tool only -- hides New Horizons tree/canopy visuals (native Valheim trees, terrain and all other rendering stay untouched) and draws a terrain-projected guide circle so you can measure H by eye using freefly."); _calibrationToggleKey = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Calibration Toggle Key", (KeyCode)290, "Toggles calibration mode on/off (only while Enable Calibration Mode is true)."); _calibrationIncrease1mKey = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Increase Radius 1m Key", (KeyCode)61, "Increases the calibration guide radius by 1m."); _calibrationDecrease1mKey = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Decrease Radius 1m Key", (KeyCode)45, "Decreases the calibration guide radius by 1m."); _calibrationIncrease5mKey = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Increase Radius 5m Key", (KeyCode)93, "Increases the calibration guide radius by 5m."); _calibrationDecrease5mKey = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Decrease Radius 5m Key", (KeyCode)91, "Decreases the calibration guide radius by 5m."); _calibrationIncrease25mKey = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Increase Radius 25m Key", (KeyCode)46, "Increases the calibration guide radius by 25m."); _calibrationDecrease25mKey = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Decrease Radius 25m Key", (KeyCode)44, "Decreases the calibration guide radius by 25m."); _calibrationSaveKey = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Save Calibrated Radius Key", (KeyCode)13, "Saves the current guide radius to Native Treeline Calibrated Radius and switches Native Treeline Mode to ManualCalibrated. No DLL rebuild required."); _calibrationResetKey = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Reset Calibration Key", (KeyCode)8, "Resets the in-progress guide radius back to the currently active H, without saving."); _calibrationRecordSampleKey = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Record Directional Sample Key", (KeyCode)114, "Optional multi-sample calibration: records the current guide radius as a distance sample in the direction the camera is currently facing. Use several dense-forest directions, then favour the displayed 25th percentile as a conservative radius."); _calibrationClearSamplesKey = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Clear Directional Samples Key", (KeyCode)127, "Clears all recorded directional calibration samples."); _calibrationGuideLineWidth = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Calibration Guide Line Width", 2f, new ConfigDescription("World-space width in metres of the calibration guide circle and vertical markers. v4.5.5's fixed 0.35m line was effectively invisible at 300-500m range; 2.0m is legible at typical calibration distances.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 10f), Array.Empty())); _calibrationGuideHeightOffset = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Calibration Guide Height Offset", 5f, new ConfigDescription("Metres above sampled terrain height the horizontal guide circle is drawn. Raised from v4.5.5's fixed +1m so the ring clears low undergrowth/grass.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 25f), Array.Empty())); _calibrationGuidePointCountConfig = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Calibration Guide Point Count", 256, new ConfigDescription("Number of terrain-sampled points around the 360-degree guide circle. Higher looks smoother on broken terrain at a small extra cost.", (AcceptableValueBase)(object)new AcceptableValueRange(64, 512), Array.Empty())); _showCalibrationVerticalMarkers = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Show Calibration Vertical Markers", true, "Draws 16 vertical marker posts (one every 22.5 degrees) around the guide circle so the measured radius stays visible even where the horizontal ring is hidden behind hills, trees or water."); _calibrationMarkerHeight = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Calibration Marker Height", 25f, new ConfigDescription("Metres the vertical marker posts extend upward from terrain at each marker point.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 100f), Array.Empty())); _calibrationGuideAlwaysVisible = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Calibration Guide Always Visible", true, "Best-effort: renders the guide using a high render queue so it is less likely to be lost in fog/haze. Does not bypass terrain depth occlusion (no custom ZTest-Always shader is shipped) -- use the vertical markers to read the radius through hills."); _showCalibrationTestGuide = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Show Calibration Test Guide", false, "Draws a second, small, close-range guide circle (see Calibration Test Guide Radius) so you can confirm the rendering pipeline itself works before trusting a distant 300-500m guide. Never used as H -- diagnostic only."); _calibrationTestGuideRadius = ((BaseUnityPlugin)this).Config.Bind("Native Treeline Calibration", "Calibration Test Guide Radius", 50f, new ConfigDescription("Radius in metres of the close-range test guide circle.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 200f), Array.Empty())); _enableProxyForestMasses = ((BaseUnityPlugin)this).Config.Bind("Proxy Forest Masses", "Enable Proxy Forest Masses", false, "LEGACY/DEBUG feature, default OFF. Low-poly cone/primitive proxy forest masses. The normal distant forest uses grounded atlas tree cards, grounded canopy cards and far-terrain forest tint instead. Disabling never affects atlas cards, canopy or tint, and proxies never auto-appear when atlas placement fails."); _enableProxyMassesInSwamp = ((BaseUnityPlugin)this).Config.Bind("Proxy Forest Masses", "Enable Proxy Masses In Swamp", false, "Swamp proxy masses stay disabled even if the master switch is enabled, until proven safe."); _swampTreeCardStartDistance = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Tree Card Start Distance", 180f, new ConfigDescription("Legacy/unused as of v4.5.4. Swamp tree cards can no longer begin ahead of the detected native tree distance; this setting is ignored.", (AcceptableValueBase)(object)new AcceptableValueRange(80f, 3000f), Array.Empty())); _swampTreeCardEndDistance = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Tree Card End Distance", 7500f, new ConfigDescription("Swamp atlas tree cards end here (also capped by the global Tree Card End Distance).", (AcceptableValueBase)(object)new AcceptableValueRange(1000f, 14000f), Array.Empty())); _swampNearCardDensityMultiplier = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Near Card Density Multiplier", 2.75f, new ConfigDescription("Legacy compatibility value; ignored. The exact shared Swamp Distant Tree Density multiplier is authoritative in every range band.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10f), Array.Empty())); _swampMidCardDensityMultiplier = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Mid Card Density Multiplier", 3.75f, new ConfigDescription("Legacy compatibility value; ignored. The exact shared Swamp Distant Tree Density multiplier is authoritative in every range band.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10f), Array.Empty())); _debugKey = ((BaseUnityPlugin)this).Config.Bind("Controls", "F8 Debug Key", (KeyCode)289, "Toggle the status overlay."); _showDebug = ((BaseUnityPlugin)this).Config.Bind("Diagnostics", "Show F8 Debug Overlay", false, "Show Donegal Horizon Lift diagnostics. Off by default for release."); _forestProofDiagnostic = ((BaseUnityPlugin)this).Config.Bind("Diagnostics", "Forest Proof Diagnostic", false, "When enabled, logs extra forest density and map alignment information during rebuilds. No debug geometry is created."); _debugDrawCardBases = ((BaseUnityPlugin)this).Config.Bind("Debug Visibility", "Debug Draw Card Bases", false, "When enabled, logs a small sample of final card base positions during rebuilds so hovering/ground contact can be inspected."); _groundAuthoritativePlacement = ((BaseUnityPlugin)this).Config.Bind("Forest Placement Safety", "Ground Authoritative Placement", true, "Final forest visual gate. Every tree/proxy/canopy footprint must prove real supported ground before geometry is added."); _requireExactFootprintTerrainSupport = ((BaseUnityPlugin)this).Config.Bind("Forest Placement Safety", "Require Exact Footprint Terrain Support", true, "Outside the native Valheim envelope, every footprint sample must sit on an already-built exact far-terrain tile."); _rejectAnyFootprintSampleWater = ((BaseUnityPlugin)this).Config.Bind("Forest Placement Safety", "Reject If Any Footprint Sample Is Water", true, "Reject a forest visual if any footprint sample is water, underwater, ocean, or too close to water."); _rejectAnyFootprintSampleUnsupported = ((BaseUnityPlugin)this).Config.Bind("Forest Placement Safety", "Reject If Any Footprint Sample Unsupported", true, "Reject a forest visual if any footprint sample is missing provider data or exact far-terrain support."); _maxFootprintHeightDifference = ((BaseUnityPlugin)this).Config.Bind("Forest Placement Safety", "Maximum Footprint Height Difference", 14f, new ConfigDescription("Reject non-biome cards/proxies when validated footprint ground varies more than this many metres. Biome-specific tolerances (Swamp/Mountain) override this. Wide range for uneven land (practical 2-60).", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 60f), Array.Empty())); _defaultMinimumLandAboveWater = ((BaseUnityPlugin)this).Config.Bind("Forest Placement Safety", "Default Minimum Land Above Water", 1.75f, new ConfigDescription("Minimum ground height over water for non-special biomes.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 12f), Array.Empty())); _plainsMinimumLandAboveWater = ((BaseUnityPlugin)this).Config.Bind("Forest Placement Safety", "Plains Minimum Land Above Water", 2.6f, new ConfigDescription("Minimum ground height over water for Plains/coast-like placements.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 12f), Array.Empty())); _coastalMinimumLandAboveWater = ((BaseUnityPlugin)this).Config.Bind("Forest Placement Safety", "Coastal Minimum Land Above Water", 2.2f, new ConfigDescription("Minimum ground height over water for non-swamp coastal placements.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 12f), Array.Empty())); _nonSwampNearWaterRejectRadius = ((BaseUnityPlugin)this).Config.Bind("Forest Placement Safety", "Non-Swamp Near Water Reject Radius", 32f, new ConfigDescription("Non-swamp forest visuals are rejected if nearby samples within this radius touch water/underwater terrain.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 120f), Array.Empty())); _enableSwampTreeCards = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Enable Swamp Tree Cards", false, "Swamp-specific placement: tolerates shallow/wet ground, smaller footprint, higher height-difference tolerance. Still never places on open ocean. v4.6.31: defaults to off."); _swampTreeDensityMultiplier = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Tree Density Multiplier", 5f, new ConfigDescription("Legacy compatibility value; ignored. Swamp Distant Tree Density (default 1.20) is the only biome density multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 25f), Array.Empty())); _swampFootprintRadiusScale = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Footprint Radius Scale", 0.24f, new ConfigDescription("Smaller footprint for strict swamp visible-land placement. Root-anchor validation still rejects channels and open water.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 2f), Array.Empty())); _swampMaxFootprintHeightDiff = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Maximum Footprint Height Difference", 28f, new ConfigDescription("Height-difference tolerance for swamp footprints.", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 60f), Array.Empty())); _swampAllowShallowWetGround = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Allow Shallow Wet Ground", true, "Allows supported swamp mud up to the configured 0.20m shallow-marsh depth; never permits ocean or an unsupported channel."); _swampMaxShallowWaterDepth = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Maximum Swamp Allowed Shallow Water Depth", 0.2f, new ConfigDescription("Maximum supported swamp-mud depth below the water surface.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _swampMinimumLandAboveWater = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Minimum Land Above Water", 0.12f, new ConfigDescription("Minimum terrain height above water for swamp cards. If centre support is below this, the card is rejected.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 12f), Array.Empty())); _swampNearWaterRejectRadius = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Near Water Reject Radius", 6f, new ConfigDescription("Swamp cards may appear near water, but this strict radius rejects visible open-water support.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 80f), Array.Empty())); _swampMaxCanopyCardWidth = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Maximum Canopy Card Width", 10f, new ConfigDescription("Swamp canopy/fill card visual width is clamped to the strict swamp width before validation and rendering.", (AcceptableValueBase)(object)new AcceptableValueRange(4f, 40f), Array.Empty())); _swampMaxProxyCardWidth = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Maximum Proxy Card Width", 12f, new ConfigDescription("Swamp proxy forest mass visual extent is clamped to this before validation and rendering. Proxy masses are disabled in swamp by default (Enable Proxy Masses In Swamp); this only matters if that is turned on.", (AcceptableValueBase)(object)new AcceptableValueRange(4f, 32f), Array.Empty())); _requireFinalSwampPositionRemainsSwamp = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Require Final Swamp Position Remains Swamp", true, "A candidate that qualified because its cell centre was swamp is rejected outright (never rerouted or pushed further inland) if its final, post-retry position is not itself swamp."); _maxSwampInlandRetryDistance = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Maximum Swamp Inland Retry Distance", 12f, new ConfigDescription("Caps how far a swamp candidate's water/slope retry jitter may wander from its original position before the retry is abandoned. Every other biome keeps the normal, larger retry jitter.", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 40f), Array.Empty())); _rejectSwampCardIfNoValidGround = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Reject Swamp Card If No Valid Swamp Ground Found", true, "If no retry within the inland distance above finds valid ground, the candidate is dropped rather than pushed further inland."); _minimumSwampBiomeFootprintRatio = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Minimum Swamp Biome Footprint Ratio", 0.7f, new ConfigDescription("Minimum fraction of final footprint samples whose provider biome remains Swamp.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _minimumSwampRootSupportRatio = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Minimum Swamp Root Support Ratio", 0.75f, new ConfigDescription("Minimum supported swamp-root sample ratio.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _minimumSwampFootprintSupportRatio = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Minimum Swamp Footprint Support Ratio", 0.65f, new ConfigDescription("Minimum supported final swamp-footprint sample ratio.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _swampFinalRootEmbedDepth = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Final Root Embed Depth", 0f, new ConfigDescription("Legacy compatibility value. Strict placement applies the single shared Final Root Embed Depth only.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.75f), Array.Empty())); _swampMaxFinalFloatingClearance = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Maximum Final Floating Clearance", 0.2f, new ConfigDescription("Swamp-specific compatibility ceiling; the strict global 0.20m floating limit always remains authoritative.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 2f), Array.Empty())); _debugSwampCardTypeColours = ((BaseUnityPlugin)this).Config.Bind("Swamp Diagnostics", "Debug Swamp Card Type Colours", false, "Diagnostic only, OFF by default. Tints the dedicated swamp biome-atlas material bright magenta so swamp-bucketed geometry (vs. mixed-atlas-fallback content) can be identified at a glance in-game. Does not distinguish tree-card vs. canopy-card content within that shared mesh/material -- see IMPLEMENTATION_NOTES_v4.5.8.md for why."); _enableCrossBiomeDuplicateRejection = ((BaseUnityPlugin)this).Config.Bind("Ground Placement Safety", "Enable Cross-Biome Duplicate Rejection", true, "Rejects a second ground-level (tree/biome) card that lands within tolerance of an already-accepted one in the same tile build, regardless of biome. Canopy/fill/proxy-mass cards are a separate visual layer and are never suppressed by this."); _duplicateHorizontalDistanceTolerance = ((BaseUnityPlugin)this).Config.Bind("Ground Placement Safety", "Duplicate Horizontal Distance Tolerance", 2f, new ConfigDescription("Metres. Two ground-level cards with centres this close (also used as the spatial hash cell size) are treated as duplicates.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 8f), Array.Empty())); _duplicateBaseHeightDifferenceWarning = ((BaseUnityPlugin)this).Config.Bind("Ground Placement Safety", "Duplicate Base Height Difference Warning", 1f, new ConfigDescription("A suppressed duplicate whose base height differs from the surviving card by more than this is logged/flagged as a stacked-card violation (diagnostic threshold, not itself a rejection gate).", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 10f), Array.Empty())); _duplicateFootprintOverlapThreshold = ((BaseUnityPlugin)this).Config.Bind("Ground Placement Safety", "Duplicate Footprint Overlap Threshold", 0.7f, new ConfigDescription("A second card whose approximate circular footprint overlaps an already-accepted card by at least this ratio is also treated as a duplicate, even if its centre is beyond the distance tolerance.", (AcceptableValueBase)(object)new AcceptableValueRange(0.4f, 0.95f), Array.Empty())); _enableStrictFinalHeightmapValidation = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Enable Strict Final Heightmap Validation", true, "Release invariant: every ground-reaching card is validated again at its final world X/Z and footprint before mesh vertices are committed."); _finalRootEmbedDepth = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Final Root Embed Depth", 0.1f, new ConfigDescription("Only the visible atlas root is embedded by this small amount after support is proven.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.75f), Array.Empty())); _maxFinalGroundFloatingError = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Maximum Final Floating Error", 0.2f, new ConfigDescription("Maximum rendered-root height above freshly sampled authoritative terrain.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 1f), Array.Empty())); _maxFinalGroundBurialError = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Maximum Final Burial Error", 0.6f, new ConfigDescription("Maximum rendered-root burial below freshly sampled authoritative terrain.", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 2f), Array.Empty())); _maxGroundHeightVarianceStandardCard = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Maximum Standard Card Terrain Variance", 1.5f, new ConfigDescription("Maximum supported terrain range under a standard card.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 5f), Array.Empty())); _maxGroundHeightVarianceLargeCard = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Maximum Large Card Terrain Variance", 0.75f, new ConfigDescription("Stricter supported terrain range for a card that needs splitting.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 3f), Array.Empty())); _minimumRootSupportRatio = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Minimum Root Support Ratio", 0.8f, new ConfigDescription("Minimum authoritative supported-land ratio across the visible root samples.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _minimumFootprintSupportRatio = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Minimum Footprint Support Ratio", 0.7f, new ConfigDescription("Minimum authoritative supported-land ratio across the complete final footprint.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _maximumUnsupportedSpan = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Maximum Unsupported Span", 1.5f, new ConfigDescription("Maximum distance between final support probes; wider cards receive extra samples.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 6f), Array.Empty())); _maximumStandardGroundCardWidth = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Maximum Standard Ground Card Width", 12f, new ConfigDescription("Hard visual and validation width cap for ordinary ground cards.", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 24f), Array.Empty())); _maximumSwampGroundCardWidth = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Maximum Swamp Ground Card Width", 10f, new ConfigDescription("Hard visual and validation width cap for swamp ground cards.", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 20f), Array.Empty())); _maximumPlainsGroundCardWidth = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Maximum Plains Ground Card Width", 10f, new ConfigDescription("Hard visual and validation width cap for plains ground cards.", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 20f), Array.Empty())); _maximumProxyGroundMassWidth = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Maximum Proxy Ground Mass Width", 12f, new ConfigDescription("Hard footprint and visual extent cap for ground-reaching proxy masses.", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 24f), Array.Empty())); _enableSlopeAwareCardGrounding = ((BaseUnityPlugin)this).Config.Bind("Slope-Aware Card Grounding", "Enable Slope-Aware Card Grounding", true, "Samples the complete visible bottom edge (left, quarter-left, centre, quarter-right, right, plus forward/back for mountain cards) against the same rendered-ground resolver used for base placement, after final width/rotation are known."); _maxVisibleEdgeFloatingError = ((BaseUnityPlugin)this).Config.Bind("Slope-Aware Card Grounding", "Maximum Visible Edge Floating Error", 0.12f, new ConfigDescription("Maximum allowed gap between the card's flat bottom edge and rendered ground at any sampled edge point.", (AcceptableValueBase)(object)new AcceptableValueRange(0.02f, 1f), Array.Empty())); _maxVisibleEdgeBurialError = ((BaseUnityPlugin)this).Config.Bind("Slope-Aware Card Grounding", "Maximum Visible Edge Burial Error", 1.25f, new ConfigDescription("Maximum allowed depth of the card's bottom edge below rendered ground at any sampled edge point.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 4f), Array.Empty())); _maxStandardFootprintVariation = ((BaseUnityPlugin)this).Config.Bind("Slope-Aware Card Grounding", "Maximum Standard Footprint Variation", 1.25f, new ConfigDescription("Maximum terrain height variation across the visible edge before an ordinary card is width-reduced or split.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 4f), Array.Empty())); _maxMountainFootprintVariation = ((BaseUnityPlugin)this).Config.Bind("Slope-Aware Card Grounding", "Maximum Mountain Footprint Variation", 1.75f, new ConfigDescription("Maximum terrain height variation across the visible edge before a mountain card is width-reduced or split.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 6f), Array.Empty())); _minimumAutomaticWidthScale = ((BaseUnityPlugin)this).Config.Bind("Slope-Aware Card Grounding", "Minimum Automatic Width Scale", 0.45f, new ConfigDescription("Lowest fraction of a card's original width that automatic width reduction may shrink it to before giving up and trying a split.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 1f), Array.Empty())); _enableAutomaticWidthReduction = ((BaseUnityPlugin)this).Config.Bind("Slope-Aware Card Grounding", "Enable Automatic Width Reduction", true, "When an edge fails, deterministically shrink the card's width and recheck the full visible edge before considering a split."); _enableSlopeCardSplitting = ((BaseUnityPlugin)this).Config.Bind("Slope-Aware Card Grounding", "Enable Slope Card Splitting", true, "When width reduction alone is not enough, replace the card with two smaller, independently grounded half-width cards."); _maximumSplitAttempts = ((BaseUnityPlugin)this).Config.Bind("Slope-Aware Card Grounding", "Maximum Split Attempts", 2, new ConfigDescription("Number of progressively narrower split attempts before rejecting the card outright.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); _treeCardVerticalAdjustment = ((BaseUnityPlugin)this).Config.Bind("Final Tree Vertical Adjustment", "Tree Card Vertical Adjustment", -0.2f, new ConfigDescription("Global manual offset applied once to every grounded tree/biome card's final base height, after the rendered ground surface is resolved. Negative moves cards downward, positive moves them upward, zero applies no manual adjustment.", (AcceptableValueBase)(object)new AcceptableValueRange(-5f, 2f), Array.Empty())); _mixedVerticalAdjustment = ((BaseUnityPlugin)this).Config.Bind("Final Tree Vertical Adjustment", "Mixed/Meadows Vertical Adjustment", 0f, new ConfigDescription("Additional per-biome offset added to the global adjustment for Meadows and other ordinary mixed-forest cards.", (AcceptableValueBase)(object)new AcceptableValueRange(-3f, 3f), Array.Empty())); _blackForestVerticalAdjustment = ((BaseUnityPlugin)this).Config.Bind("Final Tree Vertical Adjustment", "Black Forest Vertical Adjustment", 0f, new ConfigDescription("Additional per-biome offset added to the global adjustment for Black Forest cards.", (AcceptableValueBase)(object)new AcceptableValueRange(-3f, 3f), Array.Empty())); _swampVerticalAdjustmentFinal = ((BaseUnityPlugin)this).Config.Bind("Final Tree Vertical Adjustment", "Swamp Vertical Adjustment", 0f, new ConfigDescription("Additional per-biome offset added to the global adjustment for Swamp cards.", (AcceptableValueBase)(object)new AcceptableValueRange(-3f, 3f), Array.Empty())); _mountainVerticalAdjustmentFinal = ((BaseUnityPlugin)this).Config.Bind("Final Tree Vertical Adjustment", "Mountain Vertical Adjustment", 0f, new ConfigDescription("Additional per-biome offset added to the global adjustment for Mountain cards.", (AcceptableValueBase)(object)new AcceptableValueRange(-3f, 3f), Array.Empty())); _plainsVerticalAdjustmentFinal = ((BaseUnityPlugin)this).Config.Bind("Final Tree Vertical Adjustment", "Plains Vertical Adjustment", 0f, new ConfigDescription("Additional per-biome offset added to the global adjustment for Plains cards.", (AcceptableValueBase)(object)new AcceptableValueRange(-3f, 3f), Array.Empty())); _rejectGroundCardsOverOpenWater = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Reject Ground Cards Over Open Water", true, "Fails closed if any required final support sample is open ocean, deep water, or an unsupported channel."); _splitLargeCardsOnUnevenTerrain = ((BaseUnityPlugin)this).Config.Bind("Strict Ground Placement", "Split Large Cards On Uneven Terrain", true, "Deterministically retries an unsafe wide card at a smaller independently sampled width; otherwise rejects it."); _meadowsDistantTreeDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Meadows Distant Tree Density", 1.1f, new ConfigDescription("Dense mixed woodland with open variation.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _blackForestDistantTreeDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Black Forest Distant Tree Density", 1.4f, new ConfigDescription("The densest ordinary distant forest -- tall conifer walls and strong canopy.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _swampDistantTreeDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Swamp Distant Tree Density", 1.2f, new ConfigDescription("Dense twisted swamp silhouettes on valid swamp ground only -- see [Swamp Forest] for the placement rules that keep this off open water.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _mountainDistantTreeDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Mountain Distant Tree Density", 0.65f, new ConfigDescription("Moderate sparse-to-medium highland conifers -- deliberately well below Black Forest so exposed peaks don't get a forest wall.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _plainsDistantTreeDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Plains Distant Tree Density", 0.25f, new ConfigDescription("The least dense ordinary biome -- sparse clusters and scrub, never a Black-Forest-style wall.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _mistlandsDistantTreeDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Mistlands Distant Tree Density", 0.55f, new ConfigDescription("Moderate broken silhouettes where atmosphere permits.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _ashlandsDistantTreeDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Ashlands Distant Tree Density", 0.2f, new ConfigDescription("Safe, restrained default -- preserve biome identity until dedicated Ashlands assets are proven. Was hardcoded to 0 (no forest at all) prior to v4.6.0.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _deepNorthDistantTreeDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Deep North Distant Tree Density", 0.35f, new ConfigDescription("Safe, restrained default matching Mountain's sparse highland treatment.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _meadowsDistantCanopyDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Meadows Distant Canopy Density", 1f, new ConfigDescription("Canopy-layer density multiplier (separate visual layer from tree cards -- see Part 12).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _blackForestDistantCanopyDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Black Forest Distant Canopy Density", 1.35f, new ConfigDescription("Canopy-layer density multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _swampDistantCanopyDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Swamp Distant Canopy Density", 1.05f, new ConfigDescription("Canopy-layer density multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _mountainDistantCanopyDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Mountain Distant Canopy Density", 0.45f, new ConfigDescription("Canopy-layer density multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _plainsDistantCanopyDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Plains Distant Canopy Density", 0.1f, new ConfigDescription("Canopy-layer density multiplier -- kept very low so Plains never reads as forested from the canopy layer either.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _mistlandsDistantCanopyDensity = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Density", "Mistlands Distant Canopy Density", 0.4f, new ConfigDescription("Canopy-layer density multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _daylightTreeBrightness = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Daylight Tree Brightness", 1f, new ConfigDescription("Brightness multiplier at full daylight ambient luminance.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _lateAfternoonTreeBrightness = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Late Afternoon Tree Brightness", 0.9f, new ConfigDescription("Brightness multiplier at high-but-fading ambient luminance, between Daylight and Sunset.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _sunsetTreeBrightness = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Sunset Tree Brightness", 0.75f, new ConfigDescription("Brightness multiplier at mid ambient luminance.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _twilightTreeBrightness = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Twilight Tree Brightness", 0.55f, new ConfigDescription("Brightness multiplier between Sunset and Night, as ambient luminance keeps fading after sundown.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _nightTreeBrightness = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Night Tree Brightness", 0.3f, new ConfigDescription("Brightness multiplier at the lowest ambient luminance.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _moonlitNightTreeBrightness = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Moonlit Night Tree Brightness", 0.4f, new ConfigDescription("Brightness multiplier used instead of Night Tree Brightness when ambient luminance at night is measurably higher than the darkest observed floor (an honest proxy for 'moonlit' -- no dedicated moon-phase API is used, see IMPLEMENTATION_NOTES_v4.6.1.md).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _overcastTreeBrightness = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Overcast Tree Brightness", 0.7f, new ConfigDescription("Additional multiplier when weather is classified 'light' (moderate cloud/haze).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _stormTreeBrightness = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Storm Tree Brightness", 0.45f, new ConfigDescription("Additional multiplier when weather is classified 'blocked' (rain/storm/snow/heavy fog).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _minimumTreeLuminance = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Minimum Tree Luminance", 0.12f, new ConfigDescription("Hard floor -- distant cards never go fully black regardless of how dark day/night/weather multipliers combine.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _naturalDaylightDarkening = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Natural Daylight Darkening", true, "Master switch for this whole feature. When false, tree brightness is always 1.0 (pre-v4.6.0 behaviour when Horizon Clarity is also off)."); _biomeColourPreservation = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Biome Colour Preservation", 0.9f, new ConfigDescription("Nudges the final brightness back toward fully undarkened, bounded to a small (max 15%) softening effect -- never cancels day/night darkening outright.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _weatherColourInfluence = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Weather Colour Influence", 0.1f, new ConfigDescription("How strongly storm/overcast dampening affects tree brightness -- 0 ignores weather for this purpose entirely, 1 applies the full Storm/Overcast Tree Brightness multipliers.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _lightingTransitionSeconds = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Lighting Transition Seconds", 5f, new ConfigDescription("Seconds for shared tree-card RGB lighting to blend to the current daylight/weather target. Alpha remains independent.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 30f), Array.Empty())); _midDistanceOriginalColourStrength = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Mid Distance Original Colour Strength", 0.9f, new ConfigDescription("Zone 2 (mid-distance, normal-size chunks closer than the far end of the forest) original-colour retention strength, blended in via the existing Biome Colour Preservation pipeline.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _farDistanceOriginalColourStrength = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Far Distance Original Colour Strength", 0.75f, new ConfigDescription("Zone 3 (far/horizon forest) original-colour retention strength -- lower than Zone 2, allowing more atmospheric influence toward the horizon.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _farDistanceAtmosphericInfluence = ((BaseUnityPlugin)this).Config.Bind("Biome Distant Forest Lighting", "Far Distance Atmospheric Influence", 0.25f, new ConfigDescription("Zone 3 (far/horizon forest) atmospheric contribution -- complements Far Distance Original Colour Strength (documented explicitly rather than left implicit, same pattern as Clear Weather Atmospheric Colour Strength).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _preserveOriginalColourNearHandoff = ((BaseUnityPlugin)this).Config.Bind("Near Handoff Tree Colour", "Preserve Original Colour Near Handoff", true, "When true, cards within Near Handoff Colour Band Width of H skip the horizon-clarity/haze distance-darkening pass entirely and blend toward their original atlas/biome colour by Near Handoff Daylight Original Colour Strength, while still following the normal day/night brightness curve (so they still darken at night)."); _nearHandoffColourBandWidth = ((BaseUnityPlugin)this).Config.Bind("Near Handoff Tree Colour", "Near Handoff Colour Band Width", 800f, new ConfigDescription("Zone 1 width in metres. Every forest chunk size whose bounds overlap this range receives neutral original-colour tinting in daylight and natural darkening at night.", (AcceptableValueBase)(object)new AcceptableValueRange(64f, 1600f), Array.Empty())); _nearHandoffDaylightOriginalColourStrength = ((BaseUnityPlugin)this).Config.Bind("Near Handoff Tree Colour", "Near Handoff Daylight Original Colour Strength", 1f, new ConfigDescription("How strongly near-handoff cards blend toward full original colour (1.0) instead of the day/night-only brightness value.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _nearHandoffWeatherColourInfluence = ((BaseUnityPlugin)this).Config.Bind("Near Handoff Tree Colour", "Near Handoff Weather Colour Influence", 0.05f, new ConfigDescription("Weather (storm/overcast) influence applied to near-handoff cards -- independent of, and by default lower than, the global Weather Colour Influence used for the rest of the forest.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _nearHandoffFogColourInfluence = ((BaseUnityPlugin)this).Config.Bind("Near Handoff Tree Colour", "Near Handoff Fog Colour Influence", 0f, new ConfigDescription("Native fog-colour luminance influence on Zone 1 tree-card lighting.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _nearHandoffMinimumDaylightBrightness = ((BaseUnityPlugin)this).Config.Bind("Near Handoff Tree Colour", "Near Handoff Minimum Daylight Brightness", 0.95f, new ConfigDescription("Lower clamp on the near-handoff brightness multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1.5f), Array.Empty())); _nearHandoffMaximumDaylightBrightness = ((BaseUnityPlugin)this).Config.Bind("Near Handoff Tree Colour", "Near Handoff Maximum Daylight Brightness", 1.05f, new ConfigDescription("Upper clamp on the near-handoff brightness multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 2f), Array.Empty())); _useNeutralAtlasNormals = ((BaseUnityPlugin)this).Config.Bind("Near Handoff Tree Colour", "Use Neutral Atlas Normals", true, "Use stable world-up normals for all atlas billboards. This removes bright-side/dark-side strips on crossed cards while explicit day/night property blocks retain natural time-of-day darkening."); _enableTrueColourDistantLand = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Enable Original Distant Land Colour", true, "Uses one continuous provider-colour contract across Handoff, Near, Mid, Far and Horizon terrain during eligible clear daylight."); _clearWeatherOriginalTerrainColourStrength = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Original Provider Colour Strength", 1f, new ConfigDescription("Final clear-day strength of the original provider hue, saturation and luminance.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 1f), Array.Empty())); _clearWeatherAtmosphericColourStrength = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Atmospheric Colour Strength During Clear Day", 0f, new ConfigDescription("Optional atmospheric contribution retained only in the final clear-day terrain colour stage.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.5f), Array.Empty())); _clearWeatherMaximumTerrainDarkening = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Distance Brightness Loss During Clear Day", 0f, new ConfigDescription("Maximum luminance loss allowed after final provider-colour correction. Zero preserves provider luminance exactly.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.6f), Array.Empty())); _clearWeatherDistantSaturationStrength = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Distance Saturation Loss During Clear Day", 0f, new ConfigDescription("Maximum provider saturation loss allowed after final clear-day correction. Zero preserves provider saturation exactly.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 0.6f), Array.Empty())); _radialTerrainColourTransitionWidth = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Radial Terrain Colour Transition Width", 500f, new ConfigDescription("Safety blend width around the native/New Horizons handoff. With the default identical provider colour contract the blend is inactive and visually invisible.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2000f), Array.Empty())); _trueColourBlendSeconds = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "True Colour Blend Seconds", 6f, new ConfigDescription("Seconds for the independent weather/biome true-colour amount to blend to its new target.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 30f), Array.Empty())); _useFullResolutionProviderTerrainColour = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Use Full Resolution Provider Terrain Colour", true, "When the active provider exposes a full-resolution terrain colour texture, map it directly with global world UVs instead of baking each large far-terrain tile into a low-resolution solid-looking texture."); _useUntintedProviderTerrainColourMap = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Use Untinted Provider Terrain Colour Map", true, "Use the provider's original terrain colour map instead of the older forest-green overlay. Tree cards carry forest colour; native fog/weather still provides atmospheric depth."); _fallbackTerrainColourTextureResolution = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Fallback Terrain Colour Texture Resolution", 64, new ConfigDescription("Per-tile colour texture resolution used only when no full-resolution shared provider texture exists.", (AcceptableValueBase)(object)new AcceptableValueRange(32, 128), Array.Empty())); _preserveNativeTerrainLodSystemTrueColour = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Preserve Native Terrain LOD System", true, "Documentation/safety promise -- this feature adjusts New Horizons' own far-terrain meshes only; it never changes native Valheim terrain LOD distance or mesh resolution."); _preserveStormTerrainAtmosphere = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Preserve Storm Atmosphere", true, "Storm, rain, snow and heavy-fog weather blend true colour back to zero."); _preserveNightTerrainDarkness = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Preserve Night Darkness", true, "Low daylight blends true colour back to zero so night remains dark."); _preserveSunriseAndSunsetColourTrueColour = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Preserve Sunrise Sunset Colour", true, "The warm sunrise/sunset sun-elevation band retains Valheim's native atmospheric colour."); _preserveSpecialBiomeAtmosphereTerrain = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "Preserve Special Biome Atmosphere", true, "Mistlands, Ashlands and Deep North retain their native special atmosphere."); _trueColourDiagnosticTarget = ((BaseUnityPlugin)this).Config.Bind("True Colour Distant Land", "True Colour Diagnostic Target", TrueColourDiagnosticTarget.Off, "Diagnostic only; Off by default. Temporarily isolates one named native/New Horizons colour path and restores captured values when deselected. Never ship with a diagnostic target enabled."); _swampSinkIntoGround = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Sink Into Ground", 0f, new ConfigDescription("Legacy compatibility value. Strict placement uses only Final Root Embed Depth after terrain support is proven.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _swampTreeHeightMultiplier = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Tree Height Multiplier", 1.25f, new ConfigDescription("Swamp card height scale.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 3f), Array.Empty())); _swampTreeWidthMultiplier = ((BaseUnityPlugin)this).Config.Bind("Swamp Forest", "Swamp Tree Width Multiplier", 1.4f, new ConfigDescription("Swamp card width scale.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 3f), Array.Empty())); _enableMountainTreeCards = ((BaseUnityPlugin)this).Config.Bind("Mountain Forest", "Enable Mountain Tree Cards", true, "Mountain-specific placement: higher slope and height-difference tolerance, smaller footprint, density floor so ridges/slopes still get cards."); _mountainTreeDensityMultiplier = ((BaseUnityPlugin)this).Config.Bind("Mountain Forest", "Mountain Tree Density Multiplier", 4f, new ConfigDescription("Legacy compatibility value; ignored. Mountain Distant Tree Density (default 0.65) is the only biome density multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 25f), Array.Empty())); _mountainMaximumSlope = ((BaseUnityPlugin)this).Config.Bind("Mountain Forest", "Mountain Maximum Slope", 62f, new ConfigDescription("Slope tolerance for mountain cards (degrees). Overrides the generic hard slope reject on mountains.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 75f), Array.Empty())); _mountainMinimumHeight = ((BaseUnityPlugin)this).Config.Bind("Mountain Forest", "Mountain Minimum Height", 45f, new ConfigDescription("Minimum ground height for mountain cards.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 300f), Array.Empty())); _mountainFootprintRadiusScale = ((BaseUnityPlugin)this).Config.Bind("Mountain Forest", "Mountain Footprint Radius Scale", 0.45f, new ConfigDescription("Smaller footprint for mountain slopes.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 2f), Array.Empty())); _mountainMaxFootprintHeightDiff = ((BaseUnityPlugin)this).Config.Bind("Mountain Forest", "Mountain Maximum Footprint Height Difference", 42f, new ConfigDescription("Height-difference tolerance for mountain footprints.", (AcceptableValueBase)(object)new AcceptableValueRange(2f, 60f), Array.Empty())); _mountainSinkIntoGround = ((BaseUnityPlugin)this).Config.Bind("Mountain Forest", "Mountain Sink Into Ground", 0.1f, new ConfigDescription("Sink mountain card bases into ground.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _mountainTreeHeightMultiplier = ((BaseUnityPlugin)this).Config.Bind("Mountain Card Scale", "Mountain Tree Height Multiplier", 3.5f, new ConfigDescription("Post-accept Mountain card height scale.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 5f), Array.Empty())); _mountainTreeWidthMultiplier = ((BaseUnityPlugin)this).Config.Bind("Mountain Card Scale", "Mountain Tree Width Multiplier", 3f, new ConfigDescription("Post-accept Mountain final visible-crown width scale.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 5f), Array.Empty())); _mountainMinimumRandomScale = ((BaseUnityPlugin)this).Config.Bind("Mountain Card Scale", "Mountain Minimum Random Scale", 0.92f, new ConfigDescription("Lower deterministic Mountain visual-height variation.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 1.5f), Array.Empty())); _mountainMaximumRandomScale = ((BaseUnityPlugin)this).Config.Bind("Mountain Card Scale", "Mountain Maximum Random Scale", 1.22f, new ConfigDescription("Upper deterministic Mountain visual-height variation.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 2f), Array.Empty())); _mountainMinimumWidthToHeightRatio = ((BaseUnityPlugin)this).Config.Bind("Mountain Card Scale", "Mountain Minimum Width To Height Ratio", 0.5f, new ConfigDescription("Minimum final visible Mountain crown width as a fraction of final visible height.", (AcceptableValueBase)(object)new AcceptableValueRange(0.15f, 1f), Array.Empty())); _mountainMaximumWidthToHeightRatio = ((BaseUnityPlugin)this).Config.Bind("Mountain Card Scale", "Mountain Maximum Width To Height Ratio", 0.78f, new ConfigDescription("Maximum requested final visible Mountain crown width as a fraction of final visible height.", (AcceptableValueBase)(object)new AcceptableValueRange(0.15f, 1.2f), Array.Empty())); _mountainMinimumAutomaticWidthScale = ((BaseUnityPlugin)this).Config.Bind("Mountain Card Scale", "Mountain Minimum Automatic Width Scale", 0.78f, new ConfigDescription("Lowest proportional visible width/height scale allowed while fitting a Mountain card to terrain.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 1f), Array.Empty())); _maximumMountainGroundCardWidth = ((BaseUnityPlugin)this).Config.Bind("Mountain Card Scale", "Maximum Mountain Ground Card Width", 42f, new ConfigDescription("Maximum final alpha-visible Mountain crown width. Transparent atlas padding is outside this cap.", (AcceptableValueBase)(object)new AcceptableValueRange(4f, 50f), Array.Empty())); _blackForestTreeHeightMultiplier = ((BaseUnityPlugin)this).Config.Bind("Black Forest Card Scale", "Black Forest Tree Height Multiplier", 4f, new ConfigDescription("Black Forest card height scale applied after golden acceptance.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 5f), Array.Empty())); _blackForestTreeWidthMultiplier = ((BaseUnityPlugin)this).Config.Bind("Black Forest Card Scale", "Black Forest Tree Width Multiplier", 4.25f, new ConfigDescription("Black Forest final visible-crown width scale after alpha trimming.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 5f), Array.Empty())); _blackForestPineHeightMultiplier = ((BaseUnityPlugin)this).Config.Bind("Black Forest Card Scale", "Pine Height Multiplier", 1.35f, new ConfigDescription("Additional height multiplier applied once to the detected tall-pine cell after Black Forest base sizing.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 1.5f), Array.Empty())); _blackForestPineWidthMultiplier = ((BaseUnityPlugin)this).Config.Bind("Black Forest Card Scale", "Pine Width Multiplier", 1.12f, new ConfigDescription("Additional visible-crown width multiplier applied once to the detected tall-pine cell before the final visible-width ratio and cap.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 1.25f), Array.Empty())); _blackForestPineMinimumRandomScale = ((BaseUnityPlugin)this).Config.Bind("Black Forest Card Scale", "Pine Minimum Random Scale", 0.95f, new ConfigDescription("Minimum deterministic random height scale for selected tall pines.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 1.5f), Array.Empty())); _blackForestPineMaximumRandomScale = ((BaseUnityPlugin)this).Config.Bind("Black Forest Card Scale", "Pine Maximum Random Scale", 1.2f, new ConfigDescription("Maximum deterministic random height scale for selected tall pines.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 1.5f), Array.Empty())); _blackForestMinimumRandomScale = ((BaseUnityPlugin)this).Config.Bind("Black Forest Card Scale", "Black Forest Minimum Random Scale", 0.92f, new ConfigDescription("Lower bound of the deterministic per-card random size variation applied to Black Forest card height.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 1.5f), Array.Empty())); _blackForestMaximumRandomScale = ((BaseUnityPlugin)this).Config.Bind("Black Forest Card Scale", "Black Forest Maximum Random Scale", 1.25f, new ConfigDescription("Upper bound of the deterministic per-card random size variation applied to Black Forest card height.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 2f), Array.Empty())); _blackForestMinimumWidthToHeightRatio = ((BaseUnityPlugin)this).Config.Bind("Black Forest Card Scale", "Black Forest Minimum Width To Height Ratio", 0.6f, new ConfigDescription("Minimum FINAL visible crown width as a fraction of final visible height, including after slope fitting.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 1f), Array.Empty())); _blackForestMaximumWidthToHeightRatio = ((BaseUnityPlugin)this).Config.Bind("Black Forest Card Scale", "Black Forest Maximum Width To Height Ratio", 0.92f, new ConfigDescription("Maximum requested FINAL visible crown width as a fraction of final visible height.", (AcceptableValueBase)(object)new AcceptableValueRange(0.3f, 1.2f), Array.Empty())); _maximumBlackForestGroundCardWidth = ((BaseUnityPlugin)this).Config.Bind("Black Forest Card Scale", "Maximum Black Forest Ground Card Width", 48f, new ConfigDescription("Maximum FINAL alpha-visible Black Forest crown width. Transparent atlas padding is outside this cap and is never used as terrain footprint.", (AcceptableValueBase)(object)new AcceptableValueRange(4f, 56f), Array.Empty())); _blackForestMinimumAutomaticWidthScale = ((BaseUnityPlugin)this).Config.Bind("Black Forest Card Scale", "Black Forest Minimum Automatic Width Scale", 0.8f, new ConfigDescription("Lowest proportional visible width/height scale allowed while fitting a Black Forest pine to terrain.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 1f), Array.Empty())); UpgradeV4627BiomeScaleAndCanopyMinimums(); _enablePlainsSparseTreeCards = ((BaseUnityPlugin)this).Config.Bind("Plains Forest", "Enable Plains Sparse Tree Cards", true, "Sparse plains tree/scrub cards. Keeps plains mostly open."); _plainsTreeDensityMultiplier = ((BaseUnityPlugin)this).Config.Bind("Plains Forest", "Plains Tree Density Multiplier", 0.6f, new ConfigDescription("Legacy compatibility value; ignored. Plains Distant Tree Density (default 0.25) is the only biome density multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 12f), Array.Empty())); _plainsTreeHeightMultiplier = ((BaseUnityPlugin)this).Config.Bind("Plains Forest", "Plains Tree Height Multiplier", 0.75f, new ConfigDescription("Plains card height scale.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 2f), Array.Empty())); _plainsTreeWidthMultiplier = ((BaseUnityPlugin)this).Config.Bind("Plains Forest", "Plains Tree Width Multiplier", 0.85f, new ConfigDescription("Plains card width scale.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 2f), Array.Empty())); _mixedCandidateDensityFloor = ((BaseUnityPlugin)this).Config.Bind("Forest", "Mixed Candidate Density Floor", 0.25f, new ConfigDescription("Minimum candidate density for Meadows/Black Forest so cells are not thresholded out. Does not override water/ocean safety.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _swampCandidateDensityFloor = ((BaseUnityPlugin)this).Config.Bind("Forest", "Swamp Candidate Density Floor", 0.3f, new ConfigDescription("Minimum candidate density for Swamp.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _mountainCandidateDensityFloor = ((BaseUnityPlugin)this).Config.Bind("Forest", "Mountain Candidate Density Floor", 0.24f, new ConfigDescription("Minimum candidate density for Mountain.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _plainsCandidateDensityFloor = ((BaseUnityPlugin)this).Config.Bind("Forest", "Plains Candidate Density Floor", 0.04f, new ConfigDescription("Minimum candidate density for Plains (kept low so plains stay open).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _enableCardGroundLock = ((BaseUnityPlugin)this).Config.Bind("Card Ground Lock", "Enable Card Ground Lock", true, "Final universal ground gate for ALL card types (tree, canopy, biome, proxy/mass, duplicates). Locks the card base to sampled terrain and rejects any card that would float. Better to reject a card than float one."); _cardBaseHeightMode = ((BaseUnityPlugin)this).Config.Bind("Card Ground Lock", "Card Base Height Mode", CardBaseHeightMode.LowestSupportedGround, "Which supported footprint ground value becomes the card base. LowestSupportedGround is the strict no-floating default; LowerMiddleSupportedGround is less aggressive."); _maxCardBaseAboveGround = ((BaseUnityPlugin)this).Config.Bind("Card Ground Lock", "Maximum Card Base Above Ground", 0.03f, new ConfigDescription("If the locked base sits more than this above the lowest proven visible-land sample, it is lowered to this cap.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 2f), Array.Empty())); _rejectIfFinalBaseFloats = ((BaseUnityPlugin)this).Config.Bind("Card Ground Lock", "Reject If Final Base Floats", true, "If the final base would still float above the centre terrain beyond Final Base Float Tolerance, reject the card instead of showing it."); _finalBaseFloatTolerance = ((BaseUnityPlugin)this).Config.Bind("Card Ground Lock", "Final Base Float Tolerance", 0.06f, new ConfigDescription("Maximum metres a final card base may sit above proven visible terrain before the card is rejected.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _rejectIfTerrainSupportUncertain = ((BaseUnityPlugin)this).Config.Bind("Card Ground Lock", "Reject If Terrain Support Uncertain", true, "Reject a card if any footprint sample lacks provider data or exact far-terrain support."); _rejectDistantUnsupportedCards = ((BaseUnityPlugin)this).Config.Bind("Card Ground Lock", "Reject Distant Unsupported Cards", true, "Fail closed on distant/horizon land that cannot prove terrain support."); _applyGroundLockToTreeCards = ((BaseUnityPlugin)this).Config.Bind("Card Ground Lock", "Apply Ground Lock To Tree Cards", true, "Apply the strict final ground lock to mixed tree cards."); _applyGroundLockToBiomeCards = ((BaseUnityPlugin)this).Config.Bind("Card Ground Lock", "Apply Ground Lock To Biome Cards", true, "Apply the strict final ground lock to swamp, mountain and plains biome cards."); _applyGroundLockToProxyForests = ((BaseUnityPlugin)this).Config.Bind("Card Ground Lock", "Apply Ground Lock To Proxy Forests", true, "Apply the strict ground lock to low-poly proxy/continuity forest masses too."); _applyGroundLockToCanopyCards = ((BaseUnityPlugin)this).Config.Bind("Card Ground Lock", "Apply Ground Lock To Canopy Cards", true, "Apply the strict ground lock to canopy cards too."); _applyGroundLockToFillCards = ((BaseUnityPlugin)this).Config.Bind("Card Ground Lock", "Apply Ground Lock To Fill Cards", true, "Apply the strict ground lock to duplicate/fill cards too."); _enableVisibleLandSupportGate = ((BaseUnityPlugin)this).Config.Bind("Visible Land Support", "Enable Visible Land Support Gate", true, "Require generated forest visuals to prove visible dry land support instead of accepting terrain hidden under water."); _rejectCardsBelowWaterSurface = ((BaseUnityPlugin)this).Config.Bind("Visible Land Support", "Reject Cards Below Water Surface", true, "Reject when the centre or final support is below the visible water surface."); _minimumVisibleLandSamples = ((BaseUnityPlugin)this).Config.Bind("Visible Land Support", "Minimum Visible Land Samples", 4, new ConfigDescription("Minimum footprint samples that must be proven visible land.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 9), Array.Empty())); _requiredVisibleLandSampleRatio = ((BaseUnityPlugin)this).Config.Bind("Visible Land Support", "Required Visible Land Sample Ratio", 0.7f, new ConfigDescription("Required fraction of footprint samples that must be proven visible land; the strict accessor also enforces its biome-specific minimum.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _minimumBaseAboveWater = ((BaseUnityPlugin)this).Config.Bind("Visible Land Support", "Minimum Base Above Water", 0.1f, new ConfigDescription("Default minimum terrain clearance above visible water for card support.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); _swampMinimumBaseAboveWater = ((BaseUnityPlugin)this).Config.Bind("Visible Land Support", "Swamp Minimum Base Above Water", 0.12f, new ConfigDescription("Swamp-specific minimum terrain clearance above visible water.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 5f), Array.Empty())); _rejectOpenWaterCards = ((BaseUnityPlugin)this).Config.Bind("Visible Land Support", "Reject Open Water Cards", true, "Reject cards whose footprint touches open water or ocean samples."); _rejectCoastlineEdgeFloaters = ((BaseUnityPlugin)this).Config.Bind("Visible Land Support", "Reject Coastline Edge Floaters", true, "Use a stricter visible-land ratio when any footprint sample looks coastal or water-covered."); _coastlineVisibleLandSampleRatio = ((BaseUnityPlugin)this).Config.Bind("Visible Land Support", "Coastline Visible Land Sample Ratio", 0.9f, new ConfigDescription("Required visible-land ratio when water/coastline samples are present.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _distantCardsRequireExactVisibleLandSupport = ((BaseUnityPlugin)this).Config.Bind("Visible Land Support", "Distant Cards Require Exact Visible Land Support", true, "Distant/horizon cards fail closed unless exact terrain support is already available."); _rejectIfWaterBetweenSamples = ((BaseUnityPlugin)this).Config.Bind("Visible Land Support", "Reject If Water Between Samples", true, "Also probe halfway between centre and footprint samples; reject if water appears between them."); _failClosedIfSupportUncertain = ((BaseUnityPlugin)this).Config.Bind("Visible Land Support", "Fail Closed If Support Uncertain", true, "Reject if provider, water, exact terrain support, or visible-land support cannot be proven."); _enableTrunkAnchorGrounding = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Enable Trunk Anchor Grounding", true, "Requires every visible tree-card plane to prove dry supported terrain at its actual bottom-centre trunk/root anchor before vertices are added."); _rootAnchorMode = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Root Anchor Mode", RootAnchorMode.BottomCenter, "BottomCenter anchors validation to the same bottom-centre point and orientation used by the final atlas-card quad."); _rootAnchorForwardOffset = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Root Anchor Forward Offset", 0f, new ConfigDescription("Metres to move the root anchor along the card-facing vector.", (AcceptableValueBase)(object)new AcceptableValueRange(-5f, 5f), Array.Empty())); _rootAnchorSideOffset = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Root Anchor Side Offset", 0f, new ConfigDescription("Metres to move the root anchor along the card-width vector.", (AcceptableValueBase)(object)new AcceptableValueRange(-5f, 5f), Array.Empty())); _rootAnchorSampleRadius = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Root Anchor Sample Radius", 0.75f, new ConfigDescription("Radius in metres for the root centre, forward, backward, left, right and optional diagonal samples.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 6f), Array.Empty())); _rootAnchorExtraSamples = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Root Anchor Extra Samples", true, "Adds four tiny diagonal root samples around each card plane."); _rootAnchorMinimumSamples = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Root Anchor Minimum Samples", 3, new ConfigDescription("Minimum number of proven dry root samples required before a tree plane can be added.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 9), Array.Empty())); _rootAnchorRequiredDryRatio = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Root Anchor Required Dry Ratio", 0.8f, new ConfigDescription("Required supported-land fraction across the root sample pattern.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _rootAnchorMaximumAboveGround = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Root Anchor Maximum Above Ground", 0.03f, new ConfigDescription("Reject if the locked visual root sits farther above proven root terrain than this value.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _rootAnchorFloatTolerance = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Root Anchor Float Tolerance", 0.06f, new ConfigDescription("Final fail-closed root float tolerance in metres.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _rejectIfRootAnchorBelowWater = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Reject If Root Anchor Below Water", true, "Reject if the centre or any required root sample is water-covered or lacks the configured water clearance."); _rejectIfRootAnchorUnsupported = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Reject If Root Anchor Unsupported", true, "Reject if root provider data or exact distant terrain support is missing."); _rejectIfRootAnchorOverWaterChannel = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Reject If Root Anchor Over Water Channel", true, "Probe between and around root samples and reject narrow water-channel support."); _applyRootToMixedTreeCards = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Apply To Mixed Tree Cards", true, "Apply trunk/root grounding to mixed Meadows and Black Forest tree cards."); _applyRootToSwampTreeCards = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Apply To Swamp Tree Cards", true, "Apply extra-strict trunk/root grounding to swamp tree cards."); _applyRootToMountainTreeCards = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Apply To Mountain Tree Cards", true, "Apply trunk/root grounding to mountain and Deep North tree cards."); _applyRootToPlainsTreeCards = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Apply To Plains Tree Cards", true, "Apply trunk/root grounding to sparse plains tree cards."); _applyRootToFillTreeCards = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Apply To Fill Tree Cards", true, "Apply trunk/root grounding to fill and duplicate atlas cards."); _swampRootAnchorMinimumBaseAboveWater = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Swamp Root Anchor Minimum Base Above Water", 0.12f, new ConfigDescription("Minimum proven swamp root-terrain clearance above visible water.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 3f), Array.Empty())); _swampRootAnchorRequiredDryRatio = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Swamp Root Anchor Required Dry Ratio", 0.75f, new ConfigDescription("Swamp-specific supported root ratio; exact swamp biome and water-channel gates remain separate.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); _swampRejectRootNearOpenWater = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Swamp Reject Root Near Open Water", true, "Reject a swamp tree root if open water or a water channel appears in the root probe radius."); _swampRootWaterChannelProbeRadius = ((BaseUnityPlugin)this).Config.Bind("Trunk Anchor Grounding", "Swamp Root Water Channel Probe Radius", 2f, new ConfigDescription("Extra swamp root probe radius used to catch narrow channels around otherwise dry centre samples.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 12f), Array.Empty())); } private void Update() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_03db: Unknown result type (might be due to invalid IL or missing references) //IL_03e0: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_0402: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_0407: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_0515: Unknown result type (might be due to invalid IL or missing references) //IL_051a: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_048d: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_052e: Unknown result type (might be due to invalid IL or missing references) //IL_0530: Unknown result type (might be due to invalid IL or missing references) //IL_04ce: Unknown result type (might be due to invalid IL or missing references) //IL_04d2: Unknown result type (might be due to invalid IL or missing references) //IL_04c7: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Unknown result type (might be due to invalid IL or missing references) //IL_0554: Unknown result type (might be due to invalid IL or missing references) //IL_0557: Unknown result type (might be due to invalid IL or missing references) //IL_04fc: Unknown result type (might be due to invalid IL or missing references) //IL_0501: Unknown result type (might be due to invalid IL or missing references) //IL_0508: Unknown result type (might be due to invalid IL or missing references) //IL_050d: Unknown result type (might be due to invalid IL or missing references) //IL_04e9: Unknown result type (might be due to invalid IL or missing references) //IL_04f3: Unknown result type (might be due to invalid IL or missing references) //IL_04f8: Unknown result type (might be due to invalid IL or missing references) //IL_0658: Unknown result type (might be due to invalid IL or missing references) //IL_05ca: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(_debugKey.Value)) { _showDebug.Value = !_showDebug.Value; ((BaseUnityPlugin)this).Config.Save(); } if (TryConsumeReloadShortcut(out var reason)) { TriggerManualReload(reason); } if (!_enabled.Value) { HideAllTiles(); RestoreHazeIfNeeded(); RestoreTrueColourTargetDiagnostics(); RestoreCameraFarClipIfNeeded(); return; } if (!IsGameplayWorldReady(out var reason2)) { _status = "Waiting for real gameplay world: " + reason2; HideAllTiles(); RestoreHazeIfNeeded(); RestoreTrueColourTargetDiagnostics(); RestoreCameraFarClipIfNeeded(); return; } RefreshNativeTreelineCalibration(); if (!EnsureProviderReady()) { HideAllTiles(); RestoreHazeIfNeeded(); RestoreTrueColourTargetDiagnostics(); RestoreCameraFarClipIfNeeded(); return; } RefreshNativeEnvelope(); RefreshNativeTreeViewDistance(); UpdateHazeState(); UpdateTrueColourBlend(); UpdateSharedTerrainMaterialLighting(); UpdateTerrainColourRingDiagnostics(); UpdateTrueColourTargetDiagnostics(); RetryAtlasMaterialsIfNeeded(); UpdateNaturalTreeLighting(); ApplySwampDiagnosticColourIfNeeded(); if (_enableHorizonClarity.Value && _lastClarityWeather != _weatherClassification + "|" + _weatherName) { _treeRendererPropertiesDirty = true; } if (!CanRenderCustomGeometry()) { HideAllTiles(); RestoreCameraFarClipIfNeeded(); return; } _provider.UpdateBackgroundWork(0f); string worldIdentity = _provider.WorldIdentity; if (!string.IsNullOrEmpty(_lastWorldKey) && !string.Equals(worldIdentity, _lastWorldKey, StringComparison.Ordinal)) { RequestFullReload("world/provider identity changed"); return; } ApplyQuickPresetIfChanged(); ApplyTreeCardDensityPresetIfChanged(); float num = ExtensionDistance(); float num2 = NativeTreelineHandoff(); float num3 = CurrentBiomeDensitySignature(); if (!_lastAppliedExtensionDistance.HasValue || !_lastAppliedNativeTreelineHandoff.HasValue || !_lastAppliedDensitySignature.HasValue) { _lastAppliedExtensionDistance = num; _lastAppliedNativeTreelineHandoff = num2; _lastAppliedDensitySignature = num3; } else if (Mathf.Abs(num - _lastAppliedExtensionDistance.Value) > 0.5f || Mathf.Abs(num2 - _lastAppliedNativeTreelineHandoff.Value) > 0.5f || Mathf.Abs(num3 - _lastAppliedDensitySignature.Value) > 0.005f) { if (Mathf.Abs(num3 - _lastAppliedDensitySignature.Value) > 0.005f) { _pendingDensityInvalidation = true; } _lastAppliedExtensionDistance = num; _lastAppliedNativeTreelineHandoff = num2; _lastAppliedDensitySignature = num3; _pendingTreelineRebuildDebounce = 0.6f; } if (_pendingTreelineRebuildDebounce > 0f) { _pendingTreelineRebuildDebounce -= Time.unscaledDeltaTime; if (_pendingTreelineRebuildDebounce <= 0f) { if (_pendingDensityInvalidation) { _pendingDensityInvalidation = false; InvalidateAllForestTiles("biome density settings changed", immediate: false); } BeginForestOnlyRebuild("Tree range changed: H=" + Mathf.RoundToInt(num2) + "m E=" + Mathf.RoundToInt(num) + "m"); } } string text = ComputeTrueColourTierKey(); if (_lastTrueColourTierKey == null) { _lastTrueColourTierKey = text; } else if (text != _lastTrueColourTierKey) { _lastTrueColourTierKey = text; _pendingTerrainColourRebuildDebounce = (UsesFullResolutionProviderTerrainColour() ? 0f : 2f); } if (_pendingTerrainColourRebuildDebounce > 0f) { _pendingTerrainColourRebuildDebounce -= Time.unscaledDeltaTime; if (_pendingTerrainColourRebuildDebounce <= 0f) { BeginTerrainOnlyRebuild("True Colour tier changed: " + text); } } Camera worldCamera = GetWorldCamera(); ApplyCameraFarClip(worldCamera); Vector3 val = (_streamingViewOrigin = GetReferencePosition(worldCamera)); Vector3 val2 = (((Object)(object)worldCamera != (Object)null) ? ((Component)worldCamera).transform.forward : Vector3.forward); val2.y = 0f; _streamingCameraForwardFlat = ((((Vector3)(ref val2)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref val2)).normalized : Vector3.forward); float num4 = Mathf.Max(0.001f, Time.unscaledDeltaTime); _forestCameraAngularSpeed = Vector3.Angle(_lastPressureCameraForward, _streamingCameraForwardFlat) / num4; _lastPressureCameraForward = _streamingCameraForwardFlat; if (_hasStreamingVelocitySample) { float num5 = Mathf.Max(0.001f, Time.unscaledDeltaTime); Vector3 val3 = val - _lastStreamingOriginForVelocity; val3.y = 0f; _forestTeleportPressureThisFrame = ((Vector3)(ref val3)).sqrMagnitude > 2500f; Vector3 val4 = ((((Vector3)(ref val3)).sqrMagnitude <= 2500f) ? (val3 / num5) : Vector3.zero); if (((Vector3)(ref val4)).magnitude > 80f) { val4 = ((Vector3)(ref val4)).normalized * 80f; } _streamingVelocityFlat = Vector3.Lerp(_streamingVelocityFlat, val4, 0.2f); } else { _streamingVelocityFlat = Vector3.zero; _hasStreamingVelocitySample = true; _forestTeleportPressureThisFrame = false; } _lastStreamingOriginForVelocity = val; UpdateAdaptivePerformanceGovernor(); UpdateForestGenerationPressureMode(); bool flag = !_hasBuildAnchor || _rebuildRequested; float num6 = FlatDistance(val, _buildAnchor); if (flag || num6 >= ContinuityRebuildDistance()) { float num7 = ((_fastMovementRebuildDistance != null) ? _fastMovementRebuildDistance.Value : 256f); bool flag2 = flag || num6 >= num7; float num8 = Time.unscaledTime - _lastMovementSyncRealtime; if (flag2 || num8 >= EffectiveMinimumMovementSyncIntervalSeconds()) { if (flag2) { _forceImmediateTreeMaterialRefresh = true; } BeginRingRebuild(val, _rebuildRequested ? _lastRebuildReason : ("player moved " + Mathf.RoundToInt(num6) + "m")); _rebuildRequested = false; _lastMovementSyncRealtime = Time.unscaledTime; } } ProcessBuildQueues(); if (Time.unscaledTime >= _nextVisibilityUpdate) { _nextVisibilityUpdate = Time.unscaledTime + ((_visibilityUpdateIntervalSeconds != null) ? Mathf.Max(0.05f, _visibilityUpdateIntervalSeconds.Value) : 0.1f); UpdateVisibility(worldCamera, val); if (_calibrationModeActive) { HideAllForestChunksForCalibration(); } } } private unsafe bool TryConsumeReloadShortcut(out string reason) { //IL_0018: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_0067: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Invalid comparison between Unknown and I4 //IL_006b: 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_00b6: Invalid comparison between Unknown and I4 reason = null; try { KeyCode val = (KeyCode)((_reloadKey == null) ? 287 : ((int)_reloadKey.Value)); KeyCode val2 = (KeyCode)((_alternateReloadKey == null) ? 278 : ((int)_alternateReloadKey.Value)); if ((int)val != 0 && Input.GetKeyDown(val)) { reason = ((object)(*(KeyCode*)(&val))/*cast due to .constrained prefix*/).ToString() + " reload key"; return true; } if ((int)val2 != 0 && val2 != val && Input.GetKeyDown(val2)) { reason = ((object)(*(KeyCode*)(&val2))/*cast due to .constrained prefix*/).ToString() + " alternate reload key"; return true; } if (_enableHardcodedReloadFallbacks == null || _enableHardcodedReloadFallbacks.Value) { if ((int)val != 278 && (int)val2 != 278 && Input.GetKeyDown((KeyCode)278)) { reason = "Home hardcoded reload fallback"; return true; } if (Input.GetKeyDown((KeyCode)114) && (Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305))) { reason = "Ctrl+R hardcoded reload fallback"; return true; } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Reload key check failed safely: " + ex.Message)); } return false; } private void TriggerManualReload(string reason) { string text = (string.IsNullOrEmpty(reason) ? "manual reload" : reason); ((BaseUnityPlugin)this).Logger.LogWarning((object)("New Horizons reload triggered by " + text + ". Re-reading config/atlases/provider and rebuilding all visual tiles.")); TryReloadConfigFromDisk(); RequestFullReload(text); } private void TryReloadConfigFromDisk() { try { MethodInfo methodInfo = ((((BaseUnityPlugin)this).Config != null) ? ((object)((BaseUnityPlugin)this).Config).GetType().GetMethod("Reload", BindingFlags.Instance | BindingFlags.Public) : null); if (methodInfo != null) { methodInfo.Invoke(((BaseUnityPlugin)this).Config, null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Config file reloaded from disk before rebuilding visual tiles."); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Config reload from disk failed; rebuilding with current in-memory values. " + ex.Message)); } } private bool IsGameplayWorldReady(out string reason) { reason = "ready"; if (_waitForGameplayWorld == null || !_waitForGameplayWorld.Value) { return true; } if (WorldGenerator.instance == null) { reason = "WorldGenerator.instance is not ready; refusing to bind to menu/startup terrain."; return false; } if ((Object)(object)Player.m_localPlayer == (Object)null) { reason = "local player is not ready; refusing to build horizon meshes in menu/character select."; return false; } if (_requireWaterSystemForProceduralWorld != null && _requireWaterSystemForProceduralWorld.Value && (Object)(object)ZoneSystem.instance == (Object)null) { reason = "ZoneSystem water level is not ready; refusing to validate tree cards against unresolved water."; return false; } return true; } private void RequestFullReload(string reason) { _status = "Reload requested: " + reason; _lastRebuildReason = reason; _rebuildRequested = true; _hasBuildAnchor = false; _nextProviderRetry = 0f; _lastWorldKey = ""; _forestAtlasReadyRealtime = -1f; _startupForestBuildFrameCounter = 0; _startupTerrainBuildFrameCounter = 0; ClearAllTiles(); DestroyMaterials(); DisposeProvider(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Reload requested. Re-reading provider data and rebuilding the horizon/forest rings. Reason: " + reason)); } private bool EnsureProviderReady() { if (_provider != null && _provider.IsReady) { return true; } if (Time.unscaledTime < _nextProviderRetry) { return false; } _nextProviderRetry = Time.unscaledTime + 3f; DisposeProvider(); string failure; IWorldDataProvider worldDataProvider = CreateProvider(out failure); if (worldDataProvider == null) { _providerFailure = failure; _status = failure; ((BaseUnityPlugin)this).Logger.LogWarning((object)failure); return false; } _provider = worldDataProvider; _lastWorldKey = _provider.WorldIdentity; CreateSharedMaterials(); _status = "World provider ready: " + _provider.ProviderName + "."; ((BaseUnityPlugin)this).Logger.LogInfo((object)(_status + " " + _providerSelectionReason)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Map exploration touched: no. Renderer is visual-only local mesh data."); return true; } private IWorldDataProvider CreateProvider(out string failure) { failure = ""; string failureReason = "not attempted"; string failureReason2 = "not attempted"; if (_worldDataMode.Value != WorldDataMode.ProceduralWorld) { BetterContinentsCustomMapProvider betterContinentsCustomMapProvider = new BetterContinentsCustomMapProvider(this); if (betterContinentsCustomMapProvider.TryInitialize(out failureReason)) { _providerSelectionReason = ((_worldDataMode.Value == WorldDataMode.Auto) ? "Auto selected BetterContinentsCustomMap because the exact custom-map sampler is ready." : "Forced BetterContinentsCustomMap by config."); return betterContinentsCustomMapProvider; } betterContinentsCustomMapProvider.Dispose(); if (_worldDataMode.Value == WorldDataMode.BetterContinentsCustomMap) { failure = "Forced BetterContinentsCustomMap provider failed safely: " + failureReason; return null; } } if (_worldDataMode.Value != WorldDataMode.BetterContinentsCustomMap) { ProceduralWorldProvider proceduralWorldProvider = new ProceduralWorldProvider(this); if (proceduralWorldProvider.TryInitialize(out failureReason2)) { _providerSelectionReason = ((_worldDataMode.Value == WorldDataMode.Auto) ? ("Auto selected ProceduralWorld because BetterContinents was not ready/present. BetterContinents failure: " + failureReason) : "Forced ProceduralWorld by config."); return proceduralWorldProvider; } proceduralWorldProvider.Dispose(); } failure = "No world provider available. BetterContinents: " + failureReason + " | ProceduralWorld: " + failureReason2; return null; } private void CreateSharedMaterials() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) DestroyMaterials(); Texture2D val = ((_provider != null) ? _provider.SharedTerrainTexture : null); if ((Object)(object)val != (Object)null) { _sharedTerrainMaterial = CreateTextureMaterial(val, "Donegal Horizon Shared Terrain Material"); } _forestMaterial = CreateColorMaterial(ParseColor(_forestTerrainTintColour.Value, new Color(0.08f, 0.26f, 0.12f, 1f)), "Donegal Horizon Low-Poly Forest Material"); LoadForestAtlases(); } private void LoadForestAtlases() { string pluginDirectory = GetPluginDirectory(); _treeCardMaterial = LoadAtlasMaterialWithLegacyFallback(pluginDirectory, _treeAtlasFile.Value, "treeatlas.png", "Donegal Horizon Fixed Tree Cards", "Tree", out _treeAtlasTexture, out _treeAtlasStatus, out _treeAtlasShader); _canopyCardMaterial = LoadAtlasMaterialWithLegacyFallback(pluginDirectory, _canopyAtlasFile.Value, "canopyatlas.png", "Donegal Horizon Canopy/Treeline Cards", "Canopy", out _canopyAtlasTexture, out _canopyAtlasStatus, out _canopyAtlasShader); _mountainBiomeCardMaterial = LoadAtlasMaterialNoFallback(pluginDirectory, _mountainBiomeAtlasFile.Value, "Donegal Horizon Mountain Biome Cards", "Mountain biome", out _mountainBiomeAtlasTexture, out _mountainBiomeAtlasStatus, out _mountainBiomeAtlasShader); _swampBiomeCardMaterial = LoadAtlasMaterialNoFallback(pluginDirectory, _swampBiomeAtlasFile.Value, "Donegal Horizon Swamp Biome Cards", "Swamp biome", out _swampBiomeAtlasTexture, out _swampBiomeAtlasStatus, out _swampBiomeAtlasShader); if ((Object)(object)_treeAtlasTexture != (Object)null && (Object)(object)_canopyAtlasTexture != (Object)null && (Object)(object)_mountainBiomeAtlasTexture != (Object)null && (Object)(object)_swampBiomeAtlasTexture != (Object)null && ((Object)(object)_treeCardMaterial == (Object)null || (Object)(object)_canopyCardMaterial == (Object)null || (Object)(object)_mountainBiomeCardMaterial == (Object)null || (Object)(object)_swampBiomeCardMaterial == (Object)null)) { ReportForestAtlasTextureWaitOnce(); } else if ((Object)(object)_swampBiomeAtlasTexture == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Swamp biome atlas texture failed to load: " + _swampBiomeAtlasStatus + ".")); } AnalyzeAtlasVisibleBounds(_treeAtlasTexture, _treeAtlasVisibleBounds, _treeAtlasVisibleRootBottomTrim, _treeAtlasVisibleWidthFraction, "tree"); AnalyzeAtlasVisibleBounds(_canopyAtlasTexture, _canopyAtlasVisibleBounds, _canopyAtlasVisibleRootBottomTrim, null, "canopy"); AnalyzeAtlasVisibleBounds(_mountainBiomeAtlasTexture, _mountainAtlasVisibleBounds, _mountainAtlasVisibleRootBottomTrim, _mountainAtlasVisibleWidthFraction, "mountain biome"); DetectBlackForestTallPineAtlasCell(_treeAtlasTexture); AnalyzeAtlasVisibleBounds(_swampBiomeAtlasTexture, _swampAtlasVisibleBounds, _swampAtlasVisibleRootBottomTrim, null, "swamp biome"); _treeAtlasMipCount = (((Object)(object)_treeAtlasTexture != (Object)null) ? ((Texture)_treeAtlasTexture).mipmapCount : 0); _canopyAtlasMipCount = (((Object)(object)_canopyAtlasTexture != (Object)null) ? ((Texture)_canopyAtlasTexture).mipmapCount : 0); _mountainAtlasMipCount = (((Object)(object)_mountainBiomeAtlasTexture != (Object)null) ? ((Texture)_mountainBiomeAtlasTexture).mipmapCount : 0); _swampAtlasMipCount = (((Object)(object)_swampBiomeAtlasTexture != (Object)null) ? ((Texture)_swampBiomeAtlasTexture).mipmapCount : 0); ((BaseUnityPlugin)this).Logger.LogInfo((object)("FOREST ATLAS MIPMAPS READY | tree=" + _treeAtlasMipCount + " canopy=" + _canopyAtlasMipCount + " mountain=" + _mountainAtlasMipCount + " swamp=" + _swampAtlasMipCount + ".")); ValidateAndReportTreeCardCutoutMaterial(); ReportForestAtlasMaterialsReadyIfComplete(); } private void ReportForestAtlasTextureWaitOnce() { if (!_forestAtlasTextureWaitLogged) { _forestAtlasTextureWaitLogged = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"FOREST ATLAS TEXTURES LOADED - waiting for compatible live Valheim vegetation material. Forest generation remains safely paused behind the atlas barrier."); } } private void ReportForestAtlasMaterialsReadyIfComplete() { if (!_forestAtlasMaterialsReadyLogged && !((Object)(object)_treeCardMaterial == (Object)null) && _treeCardCutoutMaterialValid && !((Object)(object)_canopyCardMaterial == (Object)null) && !((Object)(object)_mountainBiomeCardMaterial == (Object)null) && !((Object)(object)_swampBiomeCardMaterial == (Object)null)) { _forestAtlasMaterialsReadyLogged = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"FOREST ATLAS MATERIALS READY"); } } private void AnalyzeAtlasVisibleBounds(Texture2D texture, AtlasVisibleBounds[] destination, float[] rootTrimDestination, float[] widthDestination, string layerName) { //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) if (destination == null || destination.Length < 4) { return; } for (int i = 0; i < 4; i++) { destination[i] = AtlasVisibleBounds.Full; if (rootTrimDestination != null && rootTrimDestination.Length > i) { rootTrimDestination[i] = 0f; } if (widthDestination != null && widthDestination.Length > i) { widthDestination[i] = 1f; } } if ((Object)(object)texture == (Object)null || ((Texture)texture).width < 2 || ((Texture)texture).height < 2) { return; } try { Color32[] pixels = texture.GetPixels32(); int num = ((Texture)texture).width / 2; int num2 = ((Texture)texture).height / 2; for (int j = 0; j < 4; j++) { int num3 = j & 1; int num4 = j >> 1; int num5 = num3 * num; int num6 = ((num3 == 0) ? num : ((Texture)texture).width); int num7 = ((num4 == 0) ? num2 : 0); int num8 = ((num4 == 0) ? ((Texture)texture).height : num2); int num9 = num6; int num10 = -1; int num11 = num8; int num12 = -1; for (int k = num7; k < num8; k++) { int num13 = k * ((Texture)texture).width; for (int l = num5; l < num6; l++) { if (pixels[num13 + l].a >= 52) { if (l < num9) { num9 = l; } if (l > num10) { num10 = l; } if (k < num11) { num11 = k; } if (k > num12) { num12 = k; } } } } if (num10 >= num9 && num12 >= num11) { num9 = Mathf.Max(num5, num9 - 1); num10 = Mathf.Min(num6 - 1, num10 + 1); num11 = Mathf.Max(num7, num11 - 1); num12 = Mathf.Min(num8 - 1, num12 + 1); float num14 = (float)(num9 - num5) / (float)Mathf.Max(1, num6 - num5); float num15 = ((float)(num10 - num5) + 1f) / (float)Mathf.Max(1, num6 - num5); float num16 = (float)(num11 - num7) / (float)Mathf.Max(1, num8 - num7); float num17 = ((float)(num12 - num7) + 1f) / (float)Mathf.Max(1, num8 - num7); AtlasVisibleBounds atlasVisibleBounds = (destination[j] = new AtlasVisibleBounds { MinU = Mathf.Clamp01(num14), MaxU = Mathf.Clamp01(num15), MinV = Mathf.Clamp01(num16), MaxV = Mathf.Clamp01(num17), WidthFraction = Mathf.Clamp01(num15 - num14), HeightFraction = Mathf.Clamp01(num17 - num16), Root = new Vector2(Mathf.Clamp01((num14 + num15) * 0.5f), Mathf.Clamp01(num16)) }); if (rootTrimDestination != null && rootTrimDestination.Length > j) { rootTrimDestination[j] = Mathf.Clamp(atlasVisibleBounds.MinV, 0f, 0.25f); } if (widthDestination != null && widthDestination.Length > j) { widthDestination[j] = atlasVisibleBounds.WidthFraction; } } } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Alpha-visible atlas bounds " + layerName + " widths [" + destination[0].WidthFraction.ToString("F3", CultureInfo.InvariantCulture) + ", " + destination[1].WidthFraction.ToString("F3", CultureInfo.InvariantCulture) + ", " + destination[2].WidthFraction.ToString("F3", CultureInfo.InvariantCulture) + ", " + destination[3].WidthFraction.ToString("F3", CultureInfo.InvariantCulture) + "] heights [" + destination[0].HeightFraction.ToString("F3", CultureInfo.InvariantCulture) + ", " + destination[1].HeightFraction.ToString("F3", CultureInfo.InvariantCulture) + ", " + destination[2].HeightFraction.ToString("F3", CultureInfo.InvariantCulture) + ", " + destination[3].HeightFraction.ToString("F3", CultureInfo.InvariantCulture) + "].")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not cache " + layerName + " alpha-visible bounds; full atlas cells remain in use: " + ex.Message)); } } private Material LoadAtlasMaterialWithLegacyFallback(string pluginDir, string preferredName, string legacyName, string materialName, string layerName, out Texture2D texture, out string status, out string shader) { Material val = LoadAtlasMaterialNoFallback(pluginDir, preferredName, materialName, layerName, out texture, out status, out shader); if ((Object)(object)val != (Object)null || string.Equals(preferredName, legacyName, StringComparison.OrdinalIgnoreCase)) { return val; } string text = ResolvePath(preferredName, pluginDir); string text2 = ResolvePath(legacyName, pluginDir); bool flag = !File.Exists(text); bool flag2 = !flag && status != null && status.StartsWith("invalid:", StringComparison.OrdinalIgnoreCase); if ((flag || flag2) && File.Exists(text2)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(layerName + " atlas " + text + " is " + (flag ? "missing" : "invalid") + "; falling back to legacy " + text2 + ".")); return LoadAtlasMaterialNoFallback(pluginDir, legacyName, materialName, layerName + " legacy", out texture, out status, out shader); } return val; } private Material LoadAtlasMaterialNoFallback(string pluginDir, string fileName, string materialName, string layerName, out Texture2D texture, out string status, out string shader) { texture = null; shader = "none"; string text = ResolvePath(fileName, pluginDir); if (!File.Exists(text)) { status = "missing: " + Path.GetFileName(text); ((BaseUnityPlugin)this).Logger.LogWarning((object)(layerName + " atlas missing at " + text + ".")); return null; } try { texture = LoadPng(text, (FilterMode)1, generateMipmaps: true); if ((Object)(object)texture == (Object)null || ((Texture)texture).width <= 0 || ((Texture)texture).height <= 0) { status = "invalid: " + Path.GetFileName(text); return null; } Material val = TryCreateCutoutTextureMaterial(texture, materialName, layerName, out shader); status = (((Object)(object)val != (Object)null) ? ("ready: " + Path.GetFileName(text)) : ("waiting for compatible shader: " + Path.GetFileName(text))); ((BaseUnityPlugin)this).Logger.LogInfo((object)(layerName + " atlas loaded: " + text + " (" + ((Texture)texture).width + "x" + ((Texture)texture).height + "). Status: " + status + ".")); return val; } catch (Exception ex) { status = "invalid: " + Path.GetFileName(text); shader = "none"; ((BaseUnityPlugin)this).Logger.LogWarning((object)(layerName + " atlas could not load at " + text + ": " + ex.Message)); return null; } } private void AnalyzeAtlasVisibleRootBottomTrim(Texture2D texture, float[] destination, string layerName) { if (destination == null || destination.Length < 4) { return; } Array.Clear(destination, 0, destination.Length); if ((Object)(object)texture == (Object)null || ((Texture)texture).width < 2 || ((Texture)texture).height < 2) { return; } try { Color32[] pixels = texture.GetPixels32(); int num = ((Texture)texture).width / 2; int num2 = ((Texture)texture).height / 2; for (int i = 0; i < 4; i++) { int num3 = i & 1; int num4 = i >> 1; int num5 = num3 * num; int num6 = ((num3 == 0) ? num : ((Texture)texture).width); int num7 = ((num4 == 0) ? num2 : 0); int num8 = ((num4 == 0) ? ((Texture)texture).height : num2); int num9 = -1; for (int j = num7; j < num8; j++) { if (num9 >= 0) { break; } int num10 = j * ((Texture)texture).width; for (int k = num5; k < num6; k++) { if (pixels[num10 + k].a >= 52) { num9 = j; break; } } } if (num9 >= 0) { destination[i] = Mathf.Clamp((float)(num9 - num7) / (float)Mathf.Max(1, num8 - num7), 0f, 0.25f); } } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Visible-root atlas trim " + layerName + " [" + destination[0].ToString("F3", CultureInfo.InvariantCulture) + ", " + destination[1].ToString("F3", CultureInfo.InvariantCulture) + ", " + destination[2].ToString("F3", CultureInfo.InvariantCulture) + ", " + destination[3].ToString("F3", CultureInfo.InvariantCulture) + "].")); } catch (Exception ex) { Array.Clear(destination, 0, destination.Length); ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not inspect " + layerName + " atlas visible-root padding; using untrimmed UVs: " + ex.Message)); } } private void AnalyzeAtlasVisibleWidthFraction(Texture2D texture, float[] destination, string layerName) { if (destination == null || destination.Length < 4) { return; } for (int i = 0; i < destination.Length; i++) { destination[i] = 1f; } if ((Object)(object)texture == (Object)null || ((Texture)texture).width < 2 || ((Texture)texture).height < 2) { return; } try { Color32[] pixels = texture.GetPixels32(); int num = ((Texture)texture).width / 2; int num2 = ((Texture)texture).height / 2; for (int j = 0; j < 4; j++) { int num3 = j & 1; int num4 = j >> 1; int num5 = num3 * num; int num6 = ((num3 == 0) ? num : ((Texture)texture).width); int num7 = ((num4 == 0) ? num2 : 0); int num8 = ((num4 == 0) ? ((Texture)texture).height : num2); int num9 = -1; int num10 = -1; for (int k = num5; k < num6; k++) { bool flag = false; for (int l = num7; l < num8; l++) { if (pixels[l * ((Texture)texture).width + k].a >= 52) { flag = true; break; } } if (flag) { if (num9 < 0) { num9 = k; } num10 = k; } } destination[j] = ((num9 >= 0) ? Mathf.Clamp01((float)(num10 - num9 + 1) / (float)Mathf.Max(1, num6 - num5)) : 1f); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Visible-width atlas fraction " + layerName + " [" + destination[0].ToString("F3", CultureInfo.InvariantCulture) + ", " + destination[1].ToString("F3", CultureInfo.InvariantCulture) + ", " + destination[2].ToString("F3", CultureInfo.InvariantCulture) + ", " + destination[3].ToString("F3", CultureInfo.InvariantCulture) + "].")); } catch (Exception ex) { for (int m = 0; m < destination.Length; m++) { destination[m] = 1f; } ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not inspect " + layerName + " atlas visible-width fraction; assuming full width: " + ex.Message)); } } private int ChooseBlackForestAtlasIndex(int seed, ForestRing ring) { int num = ((_blackForestTallPineAtlasIndex >= 0) ? _blackForestTallPineAtlasIndex : 0); int result = ((num == 0) ? 1 : 0); int b = ((_provider != null) ? _provider.StableSeed : 0); int value = HashCombine(seed, b, ((int)(ring + 1) * 92821) ^ 8); if (!(Hash01(value) < BlackForestTallPineTarget(ring))) { return result; } return num; } private float GoldenBlackForestSupportAtlasWeight(int index, ForestRing ring) { bool flag = ring == ForestRing.Handoff || ring == ForestRing.Near; float num = Mathf.Clamp01(_treeAtlasVisibleWidthFraction[index]); if (num >= 0.55f) { if (!flag) { return 3f; } return 6f; } if (num >= 0.35f) { if (!flag) { return 2f; } return 1f; } if (!flag) { return 0.35f; } return 0.15f; } private int ChooseGoldenBlackForestSupportAtlasIndex(int seed, ForestRing ring) { float num = 0f; for (int i = 0; i < 4; i++) { num += GoldenBlackForestSupportAtlasWeight(i, ring); } if (num <= 0f) { return 0; } float num2 = Hash01(seed ^ 0x812F) * num; float num3 = 0f; for (int j = 0; j < 4; j++) { num3 += GoldenBlackForestSupportAtlasWeight(j, ring); if (num2 <= num3) { return j; } } return 3; } private static float BlackForestTallPineTarget(ForestRing ring) { return ring switch { ForestRing.Handoff => 0.65f, ForestRing.Near => 0.7f, ForestRing.Mid => 0.78f, ForestRing.Far => 0.85f, _ => 0.85f, }; } private void ComposeAcceptedMountainCard(float density, int seed, out float height, out float width, out int atlasIndex) { float num = Mathf.Lerp(10f, 28f, Mathf.Clamp01(density * 0.75f + Hash01(seed ^ 0x44F) * 0.25f)); float num2 = Mathf.Lerp((_mountainMinimumRandomScale != null) ? _mountainMinimumRandomScale.Value : 0.92f, (_mountainMaximumRandomScale != null) ? _mountainMaximumRandomScale.Value : 1.22f, Hash01(seed ^ 0xD3F)); float num3 = ((_mountainTreeHeightMultiplier != null) ? _mountainTreeHeightMultiplier.Value : 3.5f); height = Mathf.Clamp(num * num3 * num2, 34f, 52f); float num4 = ((_mountainMinimumWidthToHeightRatio != null) ? _mountainMinimumWidthToHeightRatio.Value : 0.5f); float num5 = ((_mountainMaximumWidthToHeightRatio != null) ? _mountainMaximumWidthToHeightRatio.Value : 0.78f); float num6 = Mathf.Lerp(num4, num5, Hash01(seed ^ 0x1169)); float num7 = ((_mountainTreeWidthMultiplier != null) ? _mountainTreeWidthMultiplier.Value : 3f); float num8 = num * num6 * num7; float num9 = Mathf.Clamp(num8, height * num4, height * num5); float num10 = Mathf.Clamp(num9, 16f, 26f); float num11 = ((_maximumMountainGroundCardWidth != null) ? _maximumMountainGroundCardWidth.Value : 42f); width = Mathf.Min(num10, num11); atlasIndex = ChooseMountainAtlasIndex(seed); _pendingMountainRequestedVisibleWidth = num8; _pendingMountainWidthCapApplied = num8 > width + 0.001f; _pendingMountainGenericCapApplied = false; } private void ComposeAcceptedBlackForestCard(float density, int seed, float distance, out float height, out float width, out int atlasIndex) { ForestRing ring = RingForDistance(distance); atlasIndex = ChooseBlackForestAtlasIndex(seed, ring); bool flag = atlasIndex == _blackForestTallPineAtlasIndex; float num = Mathf.Lerp(10f, 28f, Mathf.Clamp01(density * 0.75f + Hash01(seed ^ 0x44F) * 0.25f)); float num2 = Mathf.Lerp((flag && _blackForestPineMinimumRandomScale != null) ? _blackForestPineMinimumRandomScale.Value : ((_blackForestMinimumRandomScale != null) ? _blackForestMinimumRandomScale.Value : 0.9f), (flag && _blackForestPineMaximumRandomScale != null) ? _blackForestPineMaximumRandomScale.Value : ((_blackForestMaximumRandomScale != null) ? _blackForestMaximumRandomScale.Value : 1.25f), Hash01(seed ^ 0x159B)); float num3 = ((_blackForestTreeHeightMultiplier != null) ? _blackForestTreeHeightMultiplier.Value : 4f); float num4 = Mathf.Clamp(num * num3 * num2, 30f, 40f); height = (flag ? Mathf.Clamp(num4 * ((_blackForestPineHeightMultiplier != null) ? _blackForestPineHeightMultiplier.Value : 1.35f), 38f, 54f) : num4); float num5 = ((_blackForestMinimumWidthToHeightRatio != null) ? _blackForestMinimumWidthToHeightRatio.Value : 0.6f); float num6 = ((_blackForestMaximumWidthToHeightRatio != null) ? _blackForestMaximumWidthToHeightRatio.Value : 0.92f); float num7 = Mathf.Lerp(num5, num6, Hash01(seed ^ 0x19FD)); float num8 = ((_blackForestTreeWidthMultiplier != null) ? _blackForestTreeWidthMultiplier.Value : 4.25f); float num9 = height * num7 * num8; if (flag && _blackForestPineWidthMultiplier != null) { num9 *= _blackForestPineWidthMultiplier.Value; } num9 = Mathf.Clamp(num9, height * num5, height * num6); float num10 = ((_maximumBlackForestGroundCardWidth != null) ? _maximumBlackForestGroundCardWidth.Value : 48f); bool pendingBlackForestWidthCapApplied = num9 > num10; width = Mathf.Min(num9, num10); _pendingBlackForestRequestedVisibleWidth = num9; _pendingBlackForestWidthCapApplied = pendingBlackForestWidthCapApplied; _pendingBlackForestGenericCapApplied = false; } private static PlacementValidationResult RetargetAcceptedVisualValidation(PlacementValidationResult validation, float width, float height) { validation.ValidatedWidth = width; validation.ValidatedHeight = height; validation.RootAnchorValidated = false; validation.RootAnchorRejectReason = RootAnchorRejectReason.None; validation.RootAnchorValidationId = 0L; return validation; } private void ConstrainAcceptedBlackForestFallback(float requestedAtlasWidth, float requestedVisualHeight, out float fallbackWidth, out float fallbackHeight) { float num = ((_blackForestMinimumAutomaticWidthScale != null) ? Mathf.Clamp01(_blackForestMinimumAutomaticWidthScale.Value) : 0.8f); fallbackHeight = Mathf.Max(16f, requestedVisualHeight * num); float num2 = ((_blackForestMinimumWidthToHeightRatio != null) ? Mathf.Max(0.2f, _blackForestMinimumWidthToHeightRatio.Value) : 0.6f); float num3 = ((_maximumBlackForestGroundCardWidth != null) ? _maximumBlackForestGroundCardWidth.Value : 48f); float num4 = Mathf.Clamp(requestedAtlasWidth * num, fallbackHeight * num2, num3); fallbackWidth = num4; _blackForestScaleFallbacks++; } private void ConstrainAcceptedMountainFallback(float requestedVisibleWidth, float requestedVisualHeight, out float fallbackWidth, out float fallbackHeight) { float num = ((_mountainMinimumAutomaticWidthScale != null) ? Mathf.Clamp01(_mountainMinimumAutomaticWidthScale.Value) : 0.78f); fallbackHeight = Mathf.Max(18f, requestedVisualHeight * num); float num2 = ((_mountainMinimumWidthToHeightRatio != null) ? Mathf.Max(0.15f, _mountainMinimumWidthToHeightRatio.Value) : 0.5f); float num3 = ((_maximumMountainGroundCardWidth != null) ? _maximumMountainGroundCardWidth.Value : 42f); fallbackWidth = Mathf.Clamp(requestedVisibleWidth * num, fallbackHeight * num2, num3); } private void BuildAcceptedSupportFallback(float supportAtlasWidth, float supportHeight, int supportAtlasIndex, Biome biome, out float fallbackWidth, out float fallbackHeight) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) float[] array = (IsMountainBiomeB(biome) ? _mountainAtlasVisibleWidthFraction : _treeAtlasVisibleWidthFraction); float num = Mathf.Clamp(array[Mathf.Clamp(supportAtlasIndex, 0, 3)], 0.1f, 1f); fallbackWidth = supportAtlasWidth * num; fallbackHeight = supportHeight; } private void RecordMountainCardDimensions(float requestedHeight, float finalVisibleHeight, float requestedVisibleWidth, float finalVisibleWidth, float finalVisibleRatio, bool widthCapApplied, bool slopeReductionApplied, bool genericCapApplied) { _mountainCardDimensionSample = "requested height=" + requestedHeight.ToString("F2", CultureInfo.InvariantCulture) + " final visible height=" + finalVisibleHeight.ToString("F2", CultureInfo.InvariantCulture) + " requested visible width=" + requestedVisibleWidth.ToString("F2", CultureInfo.InvariantCulture) + " final visible width=" + finalVisibleWidth.ToString("F2", CultureInfo.InvariantCulture) + " visible W/H=" + finalVisibleRatio.ToString("F3", CultureInfo.InvariantCulture) + " cap=" + (widthCapApplied ? "yes" : "no") + " slope reduction=" + (slopeReductionApplied ? "yes" : "no") + " generic cap=" + (genericCapApplied ? "YES" : "no"); if (!_mountainCardDimensionsLogged) { _mountainCardDimensionsLogged = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("MOUNTAIN CARD DIMENSIONS | " + _mountainCardDimensionSample)); } } private void RecordBlackForestPineDimensions(float requestedHeight, float finalVisibleHeight, float requestedVisibleWidth, float finalVisibleWidth, float finalVisibleRatio, int atlasIndex, bool widthCapApplied, bool slopeReductionApplied, bool genericCapApplied) { _blackForestPineDimensionSample = "requested height=" + requestedHeight.ToString("F2", CultureInfo.InvariantCulture) + " final visible height=" + finalVisibleHeight.ToString("F2", CultureInfo.InvariantCulture) + " requested visible crown=" + requestedVisibleWidth.ToString("F2", CultureInfo.InvariantCulture) + " final visible crown=" + finalVisibleWidth.ToString("F2", CultureInfo.InvariantCulture) + " visible W/H=" + finalVisibleRatio.ToString("F3", CultureInfo.InvariantCulture) + " pine atlas cell=" + atlasIndex + " cap=" + (widthCapApplied ? "yes" : "no") + " slope reduction=" + (slopeReductionApplied ? "yes" : "no") + " generic cap accidentally applied=" + (genericCapApplied ? "YES" : "no"); if (!_blackForestPineDimensionsLogged) { _blackForestPineDimensionsLogged = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("BLACK FOREST CARD DIMENSIONS | " + _blackForestPineDimensionSample)); } } private void RecordAcceptedBlackForestAtlasSelection(int index, ForestRing ring) { int num = Mathf.Clamp(index, 0, 3); int num2 = Mathf.Clamp((int)ring, 0, 4); _blackForestAtlasCellSelections[num]++; _blackForestSelectionsByRing[num2]++; _blackForestAcceptedCardTotal++; if (num == _blackForestTallPineAtlasIndex) { _blackForestTallPineSelectionsByRing[num2]++; } float num3 = Mathf.Clamp01(_treeAtlasVisibleWidthFraction[num]); if (num3 >= 0.55f) { _blackForestBroadCellSelections++; } else if (num3 >= 0.35f) { _blackForestStandardCellSelections++; } else { _blackForestNarrowCellSelections++; } } private void DetectBlackForestTallPineAtlasCell(Texture2D texture) { int blackForestTallPineAtlasIndex = 0; try { if ((Object)(object)texture == (Object)null || ((Texture)texture).width < 2 || ((Texture)texture).height < 2) { throw new InvalidOperationException("mixed tree atlas unavailable"); } float num = float.NegativeInfinity; for (int i = 0; i < 2; i++) { AtlasVisibleBounds atlasVisibleBounds = _treeAtlasVisibleBounds[i]; float num2 = ((atlasVisibleBounds.WidthFraction > 0.0001f) ? atlasVisibleBounds.WidthFraction : 1f); float heightFraction = atlasVisibleBounds.HeightFraction; float num3 = heightFraction * heightFraction / Mathf.Max(0.05f, num2); if (num3 > num) { num = num3; blackForestTallPineAtlasIndex = i; } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Tall-pine atlas detection fell back safely: " + ex.Message)); } _blackForestTallPineAtlasIndex = blackForestTallPineAtlasIndex; ((BaseUnityPlugin)this).Logger.LogInfo((object)("BLACK FOREST TALL PINE ATLAS CELL = " + blackForestTallPineAtlasIndex.ToString(CultureInfo.InvariantCulture))); } private int ChooseMountainAtlasIndex(int seed) { float num = 0f; for (int i = 0; i < 4; i++) { num += Mathf.Max(0.05f, _mountainAtlasVisibleWidthFraction[i] * _mountainAtlasVisibleWidthFraction[i]); } if (num <= 0f) { return 0; } float num2 = Hash01(seed ^ 0xEFE9) * num; float num3 = 0f; for (int j = 0; j < 4; j++) { num3 += Mathf.Max(0.05f, _mountainAtlasVisibleWidthFraction[j] * _mountainAtlasVisibleWidthFraction[j]); if (num2 <= num3) { return j; } } return 3; } private void BeginRingRebuild(Vector3 playerPosition, string reason) { //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_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) _lastRebuildStartTime = Time.realtimeSinceStartup; _rebuildTimingPending = true; _buildAnchor = new Vector3(playerPosition.x, 0f, playerPosition.z); _hasBuildAnchor = true; if (_forceImmediateTreeMaterialRefresh) { ApplyHorizonClarityToCardMaterials(); _forceImmediateTreeMaterialRefresh = false; } _lastRebuildReason = reason; _nearestForestDensity = 0f; _remainingTreeCardPlaneBudget = GlobalTreeCardPlaneBudget(); _remainingCanopyPlaneBudget = GlobalCanopyPlaneBudget(); if (!CanRenderCustomGeometry()) { _status = "Visual geometry disabled: " + _nativeEnvelopeDetails; ((BaseUnityPlugin)this).Logger.LogWarning((object)_status); return; } SyncTerrainTilesIncremental(reason); SyncForestTilesIncremental(reason); _status = _lastQueueBudgetStatus + " || Forest " + _lastIncrementalUpdateReason; ((BaseUnityPlugin)this).Logger.LogInfo((object)(_status + " Visual exclusion " + Mathf.RoundToInt(VisualExclusionRadius()) + "m. Forest Continuity " + Mathf.RoundToInt(ContinuityStart()) + "-" + Mathf.RoundToInt(ContinuityEnd()) + "m. Provider=" + ((_provider != null) ? _provider.ProviderName : "missing") + ".")); if (_forestProofDiagnostic.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Diagnostic map sample at anchor: " + _lastMapAlignmentStatus + ". Queue budgets terrain=" + _lastTerrainBudget + ", forest=" + _lastForestBudget + ", preset=" + _qualityPreset.Value.ToString() + ".")); } } private void BeginForestOnlyRebuild(string reason) { if (_hasBuildAnchor && CanRenderCustomGeometry()) { _lastRebuildStartTime = Time.realtimeSinceStartup; _rebuildTimingPending = true; _nearestForestDensity = 0f; SyncForestTilesIncremental(reason); _lastRebuildReason = reason; } } private void ApplyQuickPresetIfChanged() { QualityPreset value = _qualityPreset.Value; if (_newHorizonsExtensionDistance == null) { return; } if (value == QualityPreset.Custom) { _lastAppliedQualityPreset = value; return; } PresetRuntimeProfile presetRuntimeProfile = ProfileForPreset(value); if (presetRuntimeProfile != null) { float num = (presetRuntimeProfile.UseWorldMaximum ? Mathf.Max(0f, ValidForestRange() - NativeTreelineHandoff()) : presetRuntimeProfile.ExtensionDistance); num = Mathf.Clamp(num, 0f, 30000f); bool flag = !_lastAppliedQualityPreset.HasValue || _lastAppliedQualityPreset.Value != value; _lastAppliedQualityPreset = value; if (flag || Mathf.Abs(_newHorizonsExtensionDistance.Value - num) > 0.01f) { _newHorizonsExtensionDistance.Value = num; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Quality preset " + value.ToString() + " enforced exact Extension E/capacity workload values; E = " + Mathf.RoundToInt(num) + "m.")); } } } private void ApplyTreeCardDensityPresetIfChanged() { if (_treeCardDensityPreset == null) { return; } TreeCardDensityPreset treeCardDensityPreset = _treeCardDensityPreset.Value; if (_autoMatchTreeDensityToQualityPreset != null && _autoMatchTreeDensityToQualityPreset.Value) { treeCardDensityPreset = TreeDensityPresetForQuality((_qualityPreset != null) ? _qualityPreset.Value : QualityPreset.Custom); if (_treeCardDensityPreset.Value != treeCardDensityPreset) { _treeCardDensityPreset.Value = treeCardDensityPreset; } } TreeCardDensityProfile treeCardDensityProfile = TreeDensityProfileForPreset(treeCardDensityPreset); if (!_treeDensityPresetInitialized) { _treeDensityPresetInitialized = true; bool flag = _preserveExistingManualTreeCardValues == null || _preserveExistingManualTreeCardValues.Value; if (flag && treeCardDensityPreset == TreeCardDensityPreset.Custom) { _manualTreeCardValuesPreserved = true; } if (flag && treeCardDensityProfile != null && !TreeDensityValuesMatch(treeCardDensityProfile)) { _treeCardDensityPreset.Value = TreeCardDensityPreset.Custom; treeCardDensityPreset = TreeCardDensityPreset.Custom; treeCardDensityProfile = null; _manualTreeCardValuesPreserved = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Existing manual tree-card values preserved; Tree Card Density Preset set to Custom. Select a named density preset explicitly to replace them."); } _lastAppliedTreeCardDensityPreset = treeCardDensityPreset; ValidateGoldenHighTreeCardProfile(); } else if (_lastAppliedTreeCardDensityPreset.HasValue && _lastAppliedTreeCardDensityPreset.Value == treeCardDensityPreset) { ValidateGoldenHighTreeCardProfile(); } else { _lastAppliedTreeCardDensityPreset = treeCardDensityPreset; if (treeCardDensityProfile != null) { ApplyTreeDensityProfile(treeCardDensityProfile); _manualTreeCardValuesPreserved = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Tree Card Density Preset " + treeCardDensityPreset.ToString() + " explicitly applied.")); ValidateGoldenHighTreeCardProfile(); } } } private static TreeCardDensityPreset TreeDensityPresetForQuality(QualityPreset quality) { return quality switch { QualityPreset.VeryLow => TreeCardDensityPreset.VeryLow, QualityPreset.Low => TreeCardDensityPreset.Low, QualityPreset.Balanced => TreeCardDensityPreset.Balanced, QualityPreset.Medium => TreeCardDensityPreset.Medium, QualityPreset.High => TreeCardDensityPreset.High, QualityPreset.Ultra => TreeCardDensityPreset.Ultra, QualityPreset.Horizon => TreeCardDensityPreset.Extreme, _ => TreeCardDensityPreset.Custom, }; } private static TreeCardDensityProfile TreeDensityProfileForPreset(TreeCardDensityPreset preset) { float factor; switch (preset) { case TreeCardDensityPreset.Custom: return null; case TreeCardDensityPreset.High: return GoldenHighDensityProfile; case TreeCardDensityPreset.VeryLow: factor = 0.35f; break; case TreeCardDensityPreset.Low: factor = 0.5f; break; case TreeCardDensityPreset.Balanced: factor = 0.68f; break; case TreeCardDensityPreset.Medium: factor = 0.84f; break; case TreeCardDensityPreset.Ultra: factor = 1.18f; break; case TreeCardDensityPreset.Extreme: factor = 1.35f; break; default: factor = 1f; break; } return ScaleGoldenHighDensityProfile(preset, factor); } private static TreeCardDensityProfile ScaleGoldenHighDensityProfile(TreeCardDensityPreset preset, float factor) { return new TreeCardDensityProfile { Preset = preset, ClusterCellSize = 18f, DensityThreshold = Mathf.Lerp(0.035f, 0f, Mathf.Clamp01(factor)), DensityMultiplier = GoldenHighDensityProfile.DensityMultiplier * factor, CandidateTotal = Mathf.Max(64, Mathf.RoundToInt((float)GoldenHighDensityProfile.CandidateTotal * factor)), CandidateStep = 48, MaximumClusters = Mathf.Max(1, Mathf.RoundToInt((float)GoldenHighDensityProfile.MaximumClusters * factor)), MaximumTreePlanes = Mathf.Max(2, Mathf.RoundToInt((float)GoldenHighDensityProfile.MaximumTreePlanes * factor)), MeadowsCoverage = Mathf.Clamp01(GoldenHighDensityProfile.MeadowsCoverage * Mathf.Min(1f, factor + 0.2f)), BlackForestCoverage = Mathf.Clamp01(GoldenHighDensityProfile.BlackForestCoverage * Mathf.Min(1f, factor + 0.25f)), NearRetention = Mathf.Clamp01(GoldenHighDensityProfile.NearRetention * Mathf.Min(1f, factor + 0.2f)), MidRetention = Mathf.Clamp01(GoldenHighDensityProfile.MidRetention * Mathf.Min(1f, factor + 0.15f)), FarRetention = Mathf.Clamp01(GoldenHighDensityProfile.FarRetention * factor), HorizonRetention = Mathf.Clamp01(GoldenHighDensityProfile.HorizonRetention * factor), HandoffGap = GoldenHighDensityProfile.HandoffGap, NearGap = GoldenHighDensityProfile.NearGap, MidGap = GoldenHighDensityProfile.MidGap, FarGap = GoldenHighDensityProfile.FarGap, HorizonGap = GoldenHighDensityProfile.HorizonGap, GlobalDistributedDensity = GoldenHighDensityProfile.GlobalDistributedDensity * factor, BlackForestDistributedDensity = GoldenHighDensityProfile.BlackForestDistributedDensity * factor, MeadowsDistributedDensity = GoldenHighDensityProfile.MeadowsDistributedDensity * factor, MountainDistributedDensity = GoldenHighDensityProfile.MountainDistributedDensity * factor, PlainsDistributedDensity = GoldenHighDensityProfile.PlainsDistributedDensity * factor, HardRejectSlope = GoldenHighDensityProfile.HardRejectSlope }; } private void ApplyTreeDensityProfile(TreeCardDensityProfile profile) { _clusterCellSize.Value = profile.ClusterCellSize; _forestDensityThreshold.Value = profile.DensityThreshold; _forestDensityMultiplier.Value = profile.DensityMultiplier; _maximumCandidateCellsPerTileBuild.Value = profile.CandidateTotal; _candidateEvaluationsPerResumableStep.Value = profile.CandidateStep; _maximumClustersPerTile.Value = profile.MaximumClusters; _maxTreeCardPlanesPerTile.Value = profile.MaximumTreePlanes; _continuousMeadowsCoverage.Value = profile.MeadowsCoverage; _continuousBlackForestCoverage.Value = profile.BlackForestCoverage; _continuousNearGridRetention.Value = profile.NearRetention; _continuousMidGridRetention.Value = profile.MidRetention; _continuousFarGridRetention.Value = profile.FarRetention; _continuousHorizonGridRetention.Value = profile.HorizonRetention; _coverageHandoffMaximumGap.Value = profile.HandoffGap; _coverageNearMaximumGap.Value = profile.NearGap; _coverageMidMaximumGap.Value = profile.MidGap; _coverageFarMaximumGap.Value = profile.FarGap; _coverageHorizonMaximumGap.Value = profile.HorizonGap; _globalDistributedTreeDensity.Value = profile.GlobalDistributedDensity; _blackForestDistributedDensity.Value = profile.BlackForestDistributedDensity; _meadowsDistributedDensity.Value = profile.MeadowsDistributedDensity; _mountainDistributedDensity.Value = profile.MountainDistributedDensity; _plainsDistributedDensity.Value = profile.PlainsDistributedDensity; _hardSlopeRejectionThreshold.Value = profile.HardRejectSlope; if (profile.Preset == TreeCardDensityPreset.High) { _blackForestTreeHeightMultiplier.Value = Mathf.Max(_blackForestTreeHeightMultiplier.Value, 4f); _blackForestTreeWidthMultiplier.Value = Mathf.Max(_blackForestTreeWidthMultiplier.Value, 4.25f); _blackForestMinimumRandomScale.Value = Mathf.Max(_blackForestMinimumRandomScale.Value, 0.92f); _blackForestMaximumRandomScale.Value = Mathf.Max(_blackForestMaximumRandomScale.Value, 1.25f); _blackForestMinimumWidthToHeightRatio.Value = Mathf.Max(_blackForestMinimumWidthToHeightRatio.Value, 0.6f); _blackForestMaximumWidthToHeightRatio.Value = Mathf.Max(_blackForestMaximumWidthToHeightRatio.Value, 0.92f); _maximumBlackForestGroundCardWidth.Value = Mathf.Max(_maximumBlackForestGroundCardWidth.Value, 48f); _blackForestMinimumAutomaticWidthScale.Value = Mathf.Max(_blackForestMinimumAutomaticWidthScale.Value, 0.8f); } } private void UpgradeV4627BiomeScaleAndCanopyMinimums() { bool flag = false; if (_mountainTreeHeightMultiplier.Value < 3.5f) { _mountainTreeHeightMultiplier.Value = 3.5f; flag = true; } if (_mountainTreeWidthMultiplier.Value < 3f) { _mountainTreeWidthMultiplier.Value = 3f; flag = true; } if (_mountainMinimumRandomScale.Value < 0.92f) { _mountainMinimumRandomScale.Value = 0.92f; flag = true; } if (_mountainMaximumRandomScale.Value < 1.22f) { _mountainMaximumRandomScale.Value = 1.22f; flag = true; } if (_mountainMinimumWidthToHeightRatio.Value < 0.5f) { _mountainMinimumWidthToHeightRatio.Value = 0.5f; flag = true; } if (_mountainMaximumWidthToHeightRatio.Value < 0.78f) { _mountainMaximumWidthToHeightRatio.Value = 0.78f; flag = true; } if (_mountainMinimumAutomaticWidthScale.Value < 0.78f) { _mountainMinimumAutomaticWidthScale.Value = 0.78f; flag = true; } if (_maximumMountainGroundCardWidth.Value < 42f) { _maximumMountainGroundCardWidth.Value = 42f; flag = true; } if (_blackForestTreeHeightMultiplier.Value < 4f) { _blackForestTreeHeightMultiplier.Value = 4f; flag = true; } if (_blackForestTreeWidthMultiplier.Value < 4.25f) { _blackForestTreeWidthMultiplier.Value = 4.25f; flag = true; } if (_blackForestMinimumRandomScale.Value < 0.92f) { _blackForestMinimumRandomScale.Value = 0.92f; flag = true; } if (_blackForestMaximumRandomScale.Value < 1.25f) { _blackForestMaximumRandomScale.Value = 1.25f; flag = true; } if (_blackForestMinimumWidthToHeightRatio.Value < 0.6f) { _blackForestMinimumWidthToHeightRatio.Value = 0.6f; flag = true; } if (_blackForestMaximumWidthToHeightRatio.Value < 0.92f) { _blackForestMaximumWidthToHeightRatio.Value = 0.92f; flag = true; } if (_maximumBlackForestGroundCardWidth.Value < 48f) { _maximumBlackForestGroundCardWidth.Value = 48f; flag = true; } if (_blackForestMinimumAutomaticWidthScale.Value < 0.8f) { _blackForestMinimumAutomaticWidthScale.Value = 0.8f; flag = true; } if (_maxCanopyPlanesPerTile.Value < 9906) { _maxCanopyPlanesPerTile.Value = 9906; flag = true; } if (_blackForestNearMinimumSubclusters.Value < 5) { _blackForestNearMinimumSubclusters.Value = 5; flag = true; } if (flag) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Raised Mountain/Black Forest visual scale, Black Forest handoff, and canopy capacity to v4.6.27 minimums; higher manual values and density/placement settings were preserved."); } } private void MigrateV4622RendererChunkDefaults() { bool flag = false; if (NearlyEqual(_forestFarChunkSize.Value, 256f)) { _forestFarChunkSize.Value = 128f; flag = true; } if (NearlyEqual(_forestVeryFarChunkSize.Value, 384f) || NearlyEqual(_forestVeryFarChunkSize.Value, 192f)) { _forestVeryFarChunkSize.Value = 160f; flag = true; } if (flag) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Migrated legacy Far/Horizon renderer chunk defaults to 128m/160m; card content was not changed."); } } private bool TreeDensityValuesMatch(TreeCardDensityProfile profile) { if (NearlyEqual(_clusterCellSize.Value, profile.ClusterCellSize) && NearlyEqual(_forestDensityThreshold.Value, profile.DensityThreshold) && NearlyEqual(_forestDensityMultiplier.Value, profile.DensityMultiplier) && _maximumCandidateCellsPerTileBuild.Value == profile.CandidateTotal && _candidateEvaluationsPerResumableStep.Value == profile.CandidateStep && _maximumClustersPerTile.Value == profile.MaximumClusters && _maxTreeCardPlanesPerTile.Value == profile.MaximumTreePlanes && NearlyEqual(_continuousMeadowsCoverage.Value, profile.MeadowsCoverage) && NearlyEqual(_continuousBlackForestCoverage.Value, profile.BlackForestCoverage) && NearlyEqual(_continuousNearGridRetention.Value, profile.NearRetention) && NearlyEqual(_continuousMidGridRetention.Value, profile.MidRetention) && NearlyEqual(_continuousFarGridRetention.Value, profile.FarRetention) && NearlyEqual(_continuousHorizonGridRetention.Value, profile.HorizonRetention) && NearlyEqual(_coverageHandoffMaximumGap.Value, profile.HandoffGap) && NearlyEqual(_coverageNearMaximumGap.Value, profile.NearGap) && NearlyEqual(_coverageMidMaximumGap.Value, profile.MidGap) && NearlyEqual(_coverageFarMaximumGap.Value, profile.FarGap) && NearlyEqual(_coverageHorizonMaximumGap.Value, profile.HorizonGap) && NearlyEqual(_globalDistributedTreeDensity.Value, profile.GlobalDistributedDensity) && NearlyEqual(_blackForestDistributedDensity.Value, profile.BlackForestDistributedDensity) && NearlyEqual(_meadowsDistributedDensity.Value, profile.MeadowsDistributedDensity) && NearlyEqual(_mountainDistributedDensity.Value, profile.MountainDistributedDensity) && NearlyEqual(_plainsDistributedDensity.Value, profile.PlainsDistributedDensity)) { return NearlyEqual(_hardSlopeRejectionThreshold.Value, profile.HardRejectSlope); } return false; } private static bool NearlyEqual(float a, float b) { return Mathf.Abs(a - b) <= 0.0005f; } private void ValidateGoldenHighTreeCardProfile() { if (!_goldenHighProfileLogged && TreeDensityValuesMatch(GoldenHighDensityProfile)) { _goldenHighProfileLogged = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"GOLDEN HIGH TREE-CARD PROFILE VALID"); } } private Vector3 GetCalibrationOrigin(Camera camera, out string originMode) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_010a: 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_0078: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0122: 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) Vector3? val = (((Object)(object)Player.m_localPlayer != (Object)null) ? new Vector3?(((Component)Player.m_localPlayer).transform.position) : ((Vector3?)null)); Vector3? val2 = (((Object)(object)camera != (Object)null) ? new Vector3?(((Component)camera).transform.position) : ((Vector3?)null)); if (val.HasValue && val2.HasValue) { float num = FlatDistance(val.Value.x, val.Value.z, val2.Value.x, val2.Value.z); bool flag = num > 6f || Mathf.Abs(val2.Value.y - val.Value.y) > 8f; originMode = (flag ? "Detached Camera" : "Player"); if (!flag) { return val.Value; } return val2.Value; } if (val2.HasValue) { originMode = "Gameplay Camera"; return val2.Value; } if (val.HasValue) { originMode = "Player"; return val.Value; } originMode = "unknown (no player or camera)"; return Vector3.zero; } private void RefreshNativeTreelineCalibration() { //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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: 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_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) if (_calibrationGateWarningRemaining > 0f) { _calibrationGateWarningRemaining -= Time.unscaledDeltaTime; } KeyCode val = (KeyCode)((_calibrationToggleKey == null) ? 290 : ((int)_calibrationToggleKey.Value)); bool flag = _enableCalibrationMode != null && _enableCalibrationMode.Value; bool flag2 = (_calibrationToggleKeyDetectedThisFrame = (int)val != 0 && Input.GetKeyDown(val)); if (flag2 && !flag) { _calibrationGateWarningRemaining = 5f; ((BaseUnityPlugin)this).Logger.LogWarning((object)"[New Horizons Treelines] Calibration toggle key pressed but Enable Calibration Mode is false in the CFG. Set Enable Calibration Mode = true to use calibration."); } if (flag2 && flag) { _calibrationModeActive = !_calibrationModeActive; if (_calibrationModeActive) { _calibrationRadius = Mathf.Clamp(NativeTreelineHandoff(), 100f, 1500f); HideAllForestChunksForCalibration(); try { Camera worldCamera = GetWorldCamera(); string originMode; Vector3 calibrationOrigin = GetCalibrationOrigin(worldCamera, out originMode); _calibrationOriginMode = originMode; UpdateCalibrationGuideCircle(calibrationOrigin, forceRebuild: true); _lastCalibrationException = "none"; } catch (Exception ex) { _lastCalibrationException = ex.Message; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[New Horizons Treelines] Calibration guide creation failed: " + ex.Message)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[New Horizons Treelines] Calibration ACTIVE (guide radius " + Mathf.RoundToInt(_calibrationRadius) + "m).")); } else { DestroyAllCalibrationVisuals(); _nextVisibilityUpdate = 0f; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[New Horizons Treelines] Calibration INACTIVE."); } } if (!flag && _calibrationModeActive) { _calibrationModeActive = false; DestroyAllCalibrationVisuals(); _nextVisibilityUpdate = 0f; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[New Horizons Treelines] Calibration INACTIVE (CFG gate disabled mid-session)."); } if (!_calibrationModeActive) { return; } if (_calibrationIncrease1mKey != null && Input.GetKeyDown(_calibrationIncrease1mKey.Value)) { AdjustCalibrationRadius(1f); } if (_calibrationDecrease1mKey != null && Input.GetKeyDown(_calibrationDecrease1mKey.Value)) { AdjustCalibrationRadius(-1f); } if (_calibrationIncrease5mKey != null && Input.GetKeyDown(_calibrationIncrease5mKey.Value)) { AdjustCalibrationRadius(5f); } if (_calibrationDecrease5mKey != null && Input.GetKeyDown(_calibrationDecrease5mKey.Value)) { AdjustCalibrationRadius(-5f); } if (_calibrationIncrease25mKey != null && Input.GetKeyDown(_calibrationIncrease25mKey.Value)) { AdjustCalibrationRadius(25f); } if (_calibrationDecrease25mKey != null && Input.GetKeyDown(_calibrationDecrease25mKey.Value)) { AdjustCalibrationRadius(-25f); } if (_calibrationSaveKey != null && Input.GetKeyDown(_calibrationSaveKey.Value)) { SaveCalibratedRadius(); } if (_calibrationResetKey != null && Input.GetKeyDown(_calibrationResetKey.Value)) { ResetCalibrationRadius(); } Camera worldCamera2 = GetWorldCamera(); if (_calibrationRecordSampleKey != null && Input.GetKeyDown(_calibrationRecordSampleKey.Value)) { RecordCalibrationSample(worldCamera2); } if (_calibrationClearSamplesKey != null && Input.GetKeyDown(_calibrationClearSamplesKey.Value)) { _calibrationSamples.Clear(); } string originMode2; Vector3 calibrationOrigin2 = GetCalibrationOrigin(worldCamera2, out originMode2); _calibrationOriginMode = originMode2; try { UpdateCalibrationGuideCircle(calibrationOrigin2, forceRebuild: false); UpdateCalibrationFacingMarker(worldCamera2, calibrationOrigin2); UpdateCalibrationTestGuide(calibrationOrigin2); _lastCalibrationException = "none"; } catch (Exception ex2) { _lastCalibrationException = ex2.Message; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[New Horizons Treelines] Calibration guide update failed: " + ex2.Message)); } } private void RecordCalibrationSample(Camera camera) { //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_0031: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)camera == (Object)null) { return; } Vector3 forward = ((Component)camera).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f) { return; } float num = Mathf.Atan2(forward.z, forward.x) * 57.29578f; if (num < 0f) { num += 360f; } for (int i = 0; i < _calibrationSamples.Count; i++) { float x = _calibrationSamples[i].x; float num2 = Mathf.Abs(Mathf.DeltaAngle(x, num)); if (num2 < 5f) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Calibration sample rejected: duplicate direction (" + num2.ToString("F1", CultureInfo.InvariantCulture) + " degrees from an existing sample).")); return; } } _calibrationSamples.Add(new Vector2(num, _calibrationRadius)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Calibration sample recorded: direction " + num.ToString("F0", CultureInfo.InvariantCulture) + " degrees, distance " + Mathf.RoundToInt(_calibrationRadius) + "m. Total samples: " + _calibrationSamples.Count + ".")); } private bool TryComputeCalibrationSampleStats(out CalibrationSampleStats stats) { //IL_0044: 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) stats = default(CalibrationSampleStats); if (_calibrationSamples.Count == 0) { return false; } List list = new List(_calibrationSamples.Count); List list2 = new List(_calibrationSamples.Count); for (int i = 0; i < _calibrationSamples.Count; i++) { list.Add(_calibrationSamples[i].y); list2.Add(_calibrationSamples[i].x); } list.Sort(); list2.Sort(); stats.Count = list.Count; stats.Min = list[0]; stats.Max = list[list.Count - 1]; stats.Median = Percentile(list, 0.5f); stats.P25 = Percentile(list, 0.25f); stats.P75 = Percentile(list, 0.75f); List list3 = new List(list.Count); for (int j = 0; j < list.Count; j++) { list3.Add(Mathf.Abs(list[j] - stats.Median)); } list3.Sort(); stats.MedianAbsoluteDeviation = Percentile(list3, 0.5f); if (list2.Count == 1) { stats.DirectionalCoverageDegrees = 0f; } else { float num = 0f; for (int k = 0; k < list2.Count; k++) { float num2 = ((k + 1 < list2.Count) ? list2[k + 1] : (list2[0] + 360f)); num = Mathf.Max(num, num2 - list2[k]); } stats.DirectionalCoverageDegrees = Mathf.Clamp(360f - num, 0f, 360f); } return true; } private static float Percentile(List sortedValues, float fraction) { if (sortedValues.Count == 1) { return sortedValues[0]; } float num = fraction * (float)(sortedValues.Count - 1); int num2 = Mathf.FloorToInt(num); int num3 = Mathf.CeilToInt(num); if (num2 == num3) { return sortedValues[num2]; } float num4 = num - (float)num2; return Mathf.Lerp(sortedValues[num2], sortedValues[num3], num4); } private void AdjustCalibrationRadius(float delta) { _calibrationRadius = Mathf.Clamp(_calibrationRadius + delta, 100f, 1500f); } private void ResetCalibrationRadius() { _calibrationRadius = Mathf.Clamp(NativeTreelineHandoff(), 100f, 1500f); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Native treeline calibration reset to current H (" + Mathf.RoundToInt(_calibrationRadius) + "m). Nothing saved.")); } private void SaveCalibratedRadius() { if (_nativeTreelineCalibratedRadius != null && _nativeTreelineMode != null) { _nativeTreelineCalibratedRadius.Value = Mathf.Clamp(_calibrationRadius, 100f, 1500f); _nativeTreelineMode.Value = NativeTreelineMode.ManualCalibrated; ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Saved Native Treeline Calibrated Radius = " + Mathf.RoundToInt(_nativeTreelineCalibratedRadius.Value) + "m and switched Native Treeline Mode to ManualCalibrated. No DLL rebuild required; the debounced tree-only rebuild will apply it shortly.")); } } private bool TrySampleCalibrationHeight(float x, float z, float originY, ref float lastValidHeight, ref bool hasLastValidHeight, out float height) { if (_provider != null && _provider.TrySample(x, z, out var sample) && sample.Valid && !float.IsNaN(sample.GroundY) && !float.IsInfinity(sample.GroundY)) { height = sample.GroundY; lastValidHeight = height; hasLastValidHeight = true; _calibrationValidSamples++; if (float.IsNaN(_calibrationMinSampledHeight) || height < _calibrationMinSampledHeight) { _calibrationMinSampledHeight = height; } if (float.IsNaN(_calibrationMaxSampledHeight) || height > _calibrationMaxSampledHeight) { _calibrationMaxSampledHeight = height; } return true; } _calibrationFailedSamples++; height = (hasLastValidHeight ? lastValidHeight : originY); return false; } private void UpdateCalibrationGuideCircle(Vector3 origin, bool forceRebuild) { //IL_002c: 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_00f1: 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_012f: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) bool flag = Mathf.Abs(_calibrationRadius - _lastCalibrationGuideRadius) > 0.05f; bool flag2 = float.IsNaN(_lastCalibrationGuideOrigin.x) || FlatDistance(origin.x, origin.z, _lastCalibrationGuideOrigin.x, _lastCalibrationGuideOrigin.z) > 0.25f; if (!forceRebuild && !flag && !flag2) { return; } EnsureCalibrationGuideObject(); if ((Object)(object)_calibrationGuideRenderer == (Object)null) { return; } int num = Mathf.Clamp((_calibrationGuidePointCountConfig != null) ? _calibrationGuidePointCountConfig.Value : 256, 64, 512); float num2 = ((_calibrationGuideHeightOffset != null) ? _calibrationGuideHeightOffset.Value : 5f); _calibrationValidSamples = 0; _calibrationFailedSamples = 0; _calibrationMinSampledHeight = float.NaN; _calibrationMaxSampledHeight = float.NaN; _calibrationGuideRenderer.positionCount = num + 1; float lastValidHeight = origin.y; bool hasLastValidHeight = false; for (int i = 0; i <= num; i++) { float num3 = (float)i / (float)num * MathF.PI * 2f; float num4 = origin.x + Mathf.Cos(num3) * _calibrationRadius; float num5 = origin.z + Mathf.Sin(num3) * _calibrationRadius; TrySampleCalibrationHeight(num4, num5, origin.y, ref lastValidHeight, ref hasLastValidHeight, out var height); float num6 = height + num2; if (float.IsNaN(num6) || float.IsInfinity(num6)) { num6 = origin.y + num2; } _calibrationGuideRenderer.SetPosition(i, new Vector3(num4, num6, num5)); } _calibrationGuidePointCount = num + 1; _lastCalibrationGuideRadius = _calibrationRadius; _lastCalibrationGuideOrigin = origin; _lastCalibrationGuideRebuildRealtime = Time.realtimeSinceStartup; if (_showCalibrationVerticalMarkers == null || _showCalibrationVerticalMarkers.Value) { EnsureCalibrationMarkerObjects(); RebuildCalibrationVerticalMarkers(origin, lastValidHeight, hasLastValidHeight); for (int j = 0; j < _calibrationMarkerRenderers.Count; j++) { ((Renderer)_calibrationMarkerRenderers[j]).enabled = true; } } else if (_calibrationMarkerRenderers.Count > 0) { for (int k = 0; k < _calibrationMarkerRenderers.Count; k++) { ((Renderer)_calibrationMarkerRenderers[k]).enabled = false; } } } private Material CreateCalibrationGuideMaterial(Color color) { //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) string[] array = new string[4] { "Sprites/Default", "UI/Default", "Unlit/Color", "Legacy Shaders/Particles/Alpha Blended" }; Shader val = null; string calibrationGuideShaderName = null; for (int i = 0; i < array.Length; i++) { val = Shader.Find(array[i]); if ((Object)(object)val != (Object)null) { calibrationGuideShaderName = array[i]; break; } } if ((Object)(object)val == (Object)null) { val = FindShader("Unlit/Color", "Legacy Shaders/Diffuse"); if ((Object)(object)val != (Object)null) { calibrationGuideShaderName = ((Object)val).name + " (proven fallback, same as far-terrain tint materials)"; } } if ((Object)(object)val == (Object)null) { _calibrationGuideShaderName = "NONE RESOLVED"; return null; } _calibrationGuideShaderName = calibrationGuideShaderName; Material val2 = new Material(val); val2.color = color; if (_calibrationGuideAlwaysVisible == null || _calibrationGuideAlwaysVisible.Value) { val2.renderQueue = 3100; } return val2; } private void ConfigureCalibrationLineRenderer(LineRenderer renderer, Material material, Color color) { //IL_0064: 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) renderer.loop = true; renderer.useWorldSpace = true; float widthMultiplier = ((_calibrationGuideLineWidth != null) ? _calibrationGuideLineWidth.Value : 2f); renderer.widthMultiplier = widthMultiplier; renderer.numCapVertices = 2; ((Renderer)renderer).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)renderer).receiveShadows = false; ((Renderer)renderer).lightProbeUsage = (LightProbeUsage)0; ((Renderer)renderer).reflectionProbeUsage = (ReflectionProbeUsage)0; if ((Object)(object)material != (Object)null) { ((Renderer)renderer).material = material; renderer.startColor = color; renderer.endColor = color; } } private void EnsureCalibrationGuideObject() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_calibrationGuideObject != (Object)null)) { _calibrationGuideObject = new GameObject("NewHorizonsTreeline_CalibrationGuide"); _calibrationGuideObject.layer = 0; _calibrationGuideRenderer = _calibrationGuideObject.AddComponent(); Color color = default(Color); ((Color)(ref color))..ctor(1f, 0.85f, 0.1f, 1f); if ((Object)(object)_calibrationGuideMaterial == (Object)null) { _calibrationGuideMaterial = CreateCalibrationGuideMaterial(color); } ConfigureCalibrationLineRenderer(_calibrationGuideRenderer, _calibrationGuideMaterial, color); } } private void EnsureCalibrationMarkerObjects() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Expected O, but got Unknown //IL_016b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_calibrationMarkerRoot != (Object)null)) { _calibrationMarkerRoot = new GameObject("NewHorizonsTreeline_CalibrationMarkers"); _calibrationMarkerRoot.layer = 0; Color color = default(Color); ((Color)(ref color))..ctor(1f, 0.3f, 0.1f, 1f); Color color2 = default(Color); ((Color)(ref color2))..ctor(0.2f, 1f, 0.3f, 1f); if ((Object)(object)_calibrationMarkerMaterial == (Object)null) { _calibrationMarkerMaterial = CreateCalibrationGuideMaterial(color); } if ((Object)(object)_calibrationFacingMarkerMaterial == (Object)null) { _calibrationFacingMarkerMaterial = CreateCalibrationGuideMaterial(color2); } for (int i = 0; i < 16; i++) { GameObject val = new GameObject("Marker_" + i); val.transform.SetParent(_calibrationMarkerRoot.transform, false); val.layer = 0; LineRenderer val2 = val.AddComponent(); val2.loop = false; val2.positionCount = 2; ConfigureCalibrationLineRenderer(val2, _calibrationMarkerMaterial, color); _calibrationMarkerRenderers.Add(val2); } GameObject val3 = new GameObject("Marker_Facing"); val3.transform.SetParent(_calibrationMarkerRoot.transform, false); val3.layer = 0; _calibrationFacingMarkerRenderer = val3.AddComponent(); _calibrationFacingMarkerRenderer.loop = false; _calibrationFacingMarkerRenderer.positionCount = 2; ConfigureCalibrationLineRenderer(_calibrationFacingMarkerRenderer, _calibrationFacingMarkerMaterial, color2); } } private void RebuildCalibrationVerticalMarkers(Vector3 origin, float fallbackGround, bool hasFallbackGround) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if (_calibrationMarkerRenderers.Count == 16) { float num = ((_calibrationMarkerHeight != null) ? _calibrationMarkerHeight.Value : 25f); float lastValidHeight = fallbackGround; bool hasLastValidHeight = hasFallbackGround; for (int i = 0; i < 16; i++) { float num2 = (float)i / 16f * MathF.PI * 2f; float num3 = origin.x + Mathf.Cos(num2) * _calibrationRadius; float num4 = origin.z + Mathf.Sin(num2) * _calibrationRadius; TrySampleCalibrationHeight(num3, num4, origin.y, ref lastValidHeight, ref hasLastValidHeight, out var height); LineRenderer val = _calibrationMarkerRenderers[i]; val.SetPosition(0, new Vector3(num3, height, num4)); val.SetPosition(1, new Vector3(num3, height + num, num4)); } } } private void UpdateCalibrationFacingMarker(Camera camera, Vector3 origin) { //IL_004c: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_calibrationFacingMarkerRenderer == (Object)null || (Object)(object)camera == (Object)null) { return; } if (_showCalibrationVerticalMarkers != null && !_showCalibrationVerticalMarkers.Value) { ((Renderer)_calibrationFacingMarkerRenderer).enabled = false; return; } ((Renderer)_calibrationFacingMarkerRenderer).enabled = true; Vector3 forward = ((Component)camera).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f) { forward = Vector3.forward; } ((Vector3)(ref forward)).Normalize(); float num = origin.x + forward.x * _calibrationRadius; float num2 = origin.z + forward.z * _calibrationRadius; float num3 = ((_calibrationMarkerHeight != null) ? _calibrationMarkerHeight.Value : 25f) * 1.5f; float lastValidHeight = origin.y; bool hasLastValidHeight = false; TrySampleCalibrationHeight(num, num2, origin.y, ref lastValidHeight, ref hasLastValidHeight, out var height); _calibrationFacingMarkerRenderer.SetPosition(0, new Vector3(num, height, num2)); _calibrationFacingMarkerRenderer.SetPosition(1, new Vector3(num, height + num3, num2)); } private void UpdateCalibrationTestGuide(Vector3 origin) { //IL_0084: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) if (_showCalibrationTestGuide == null || !_showCalibrationTestGuide.Value) { if ((Object)(object)_calibrationTestGuideObject != (Object)null) { Object.Destroy((Object)(object)_calibrationTestGuideObject); _calibrationTestGuideObject = null; _calibrationTestGuideRenderer = null; } return; } float num = ((_calibrationTestGuideRadius != null) ? _calibrationTestGuideRadius.Value : 50f); bool flag = Mathf.Abs(num - _lastCalibrationTestGuideRadius) > 0.05f; bool flag2 = float.IsNaN(_lastCalibrationTestGuideOrigin.x) || FlatDistance(origin.x, origin.z, _lastCalibrationTestGuideOrigin.x, _lastCalibrationTestGuideOrigin.z) > 0.25f; if ((Object)(object)_calibrationTestGuideObject == (Object)null) { _calibrationTestGuideObject = new GameObject("NewHorizonsTreeline_CalibrationTestGuide"); _calibrationTestGuideObject.layer = 0; _calibrationTestGuideRenderer = _calibrationTestGuideObject.AddComponent(); Color color = default(Color); ((Color)(ref color))..ctor(0.1f, 0.9f, 1f, 1f); if ((Object)(object)_calibrationTestGuideMaterial == (Object)null) { _calibrationTestGuideMaterial = CreateCalibrationGuideMaterial(color); } ConfigureCalibrationLineRenderer(_calibrationTestGuideRenderer, _calibrationTestGuideMaterial, color); } if (flag || flag2) { float num2 = ((_calibrationGuideHeightOffset != null) ? _calibrationGuideHeightOffset.Value : 5f); _calibrationTestGuideRenderer.positionCount = 97; float lastValidHeight = origin.y; bool hasLastValidHeight = false; for (int i = 0; i <= 96; i++) { float num3 = (float)i / 96f * MathF.PI * 2f; float num4 = origin.x + Mathf.Cos(num3) * num; float num5 = origin.z + Mathf.Sin(num3) * num; TrySampleCalibrationHeight(num4, num5, origin.y, ref lastValidHeight, ref hasLastValidHeight, out var height); _calibrationTestGuideRenderer.SetPosition(i, new Vector3(num4, height + num2, num5)); } _lastCalibrationTestGuideRadius = num; _lastCalibrationTestGuideOrigin = origin; } } private void DestroyAllCalibrationVisuals() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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) if ((Object)(object)_calibrationGuideObject != (Object)null) { Object.Destroy((Object)(object)_calibrationGuideObject); } _calibrationGuideObject = null; _calibrationGuideRenderer = null; _lastCalibrationGuideRadius = -1f; _lastCalibrationGuideOrigin = new Vector3(float.NaN, float.NaN, float.NaN); _calibrationGuidePointCount = 0; if ((Object)(object)_calibrationMarkerRoot != (Object)null) { Object.Destroy((Object)(object)_calibrationMarkerRoot); } _calibrationMarkerRoot = null; _calibrationMarkerRenderers.Clear(); _calibrationFacingMarkerRenderer = null; if ((Object)(object)_calibrationTestGuideObject != (Object)null) { Object.Destroy((Object)(object)_calibrationTestGuideObject); } _calibrationTestGuideObject = null; _calibrationTestGuideRenderer = null; _lastCalibrationTestGuideRadius = -1f; _lastCalibrationTestGuideOrigin = new Vector3(float.NaN, float.NaN, float.NaN); } private void HideAllForestChunksForCalibration() { foreach (ForestTile value in _forestTiles.Values) { value.SetEnabled(enabled: false); } } private void ClearTerrainTilesOnly() { _terrainQueue.Clear(); _terrainQueuedKeys.Clear(); foreach (TerrainTile value in _terrainTiles.Values) { value.Destroy(); } _terrainTiles.Clear(); } private void BeginTerrainOnlyRebuild(string reason) { if (_hasBuildAnchor && CanRenderCustomGeometry()) { ClearTerrainTilesOnly(); QueueTerrainTiles(); _lastRebuildReason = reason; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[New Horizons Treelines] " + reason)); } } private string ComputeTrueColourTierKey() { if (_enableTrueColourDistantLand == null || !_enableTrueColourDistantLand.Value) { return "off"; } string text3; if (_preserveSpecialBiomeAtmosphereTerrain == null || _preserveSpecialBiomeAtmosphereTerrain.Value) { string text = TryGetPlayerBiomeName(); if (!string.IsNullOrEmpty(text)) { string text2 = text.ToLowerInvariant(); if (text2.Contains("mistlands") || text2.Contains("ashlands") || text2.Contains("deepnorth")) { text3 = "special"; return text3 + "|" + TrueColourAmountBucket() + "|diag:" + ((_trueColourDiagnosticTarget != null) ? _trueColourDiagnosticTarget.Value.ToString() : "Off"); } } } text3 = _weatherClassification ?? "unknown"; return text3 + "|" + TrueColourAmountBucket() + "|diag:" + ((_trueColourDiagnosticTarget != null) ? _trueColourDiagnosticTarget.Value.ToString() : "Off"); } private string TrueColourAmountBucket() { float num = Mathf.Clamp01(ComputeTrueColourAmount()); return (Mathf.Round(num * 4f) / 4f).ToString("F2", CultureInfo.InvariantCulture); } private void InvalidateAllForestTiles(string reason, bool immediate) { _forestGenerationEpoch++; _determinismWarningsThisEpoch.Clear(); _forestCancelledObsoleteJobs += _forestAddQueue.Count; _forestAddQueue.Clear(); _forestAddJobsByKey.Clear(); _coverageRepairQueue.Clear(); _coverageRepairQueuedKeys.Clear(); _coverageSectorLightweightQueue.Clear(); _coverageSectorKnownKeys.Clear(); _activeCoverageAuditJobs.Clear(); Array.Clear(_ringRepairJobsPending, 0, _ringRepairJobsPending.Length); Array.Clear(_activeCoverageSectorsByRing, 0, _activeCoverageSectorsByRing.Length); Array.Clear(_coverageRemainingCellsByRing, 0, _coverageRemainingCellsByRing.Length); List list = new List(_forestTiles.Keys); for (int i = 0; i < list.Count; i++) { RetireForestTile(list[i], allowCache: false); } if (_clearPoolsOnWorldChange == null || _clearPoolsOnWorldChange.Value) { PurgeForestTileCache(); } if (immediate) { while (_forestRetirementQueue.Count > 0) { _forestRetirementQueue.Dequeue().Destroy(); } } ResetGroundGateCounters(); _lastIncrementalUpdateReason = reason; } private void PurgeForestTileCache() { foreach (ForestTile value in _forestTileCache.Values) { _forestRetirementQueue.Enqueue(value); } List list = new List(_forestTileCache.Keys); for (int i = 0; i < list.Count; i++) { DeactivateGroundCardRecordsForTile(list[i], deleteRecords: true); } _forestTileCache.Clear(); } private void RetireForestTile(long key, bool allowCache) { if (_forestTiles.TryGetValue(key, out var value) && value != null) { _forestTiles.Remove(key); if (value.IsCoverageRepair && _coverageRepairMeshBuffers.TryGetValue(key, out var value2)) { _coverageRepairMeshBuffers.Remove(key); ReturnCoverageRepairMeshBuffer(value2); } ForgetTreeRendererPropertyStates(value); DeactivateGroundCardRecordsForTile(key, !allowCache); value.SetEnabled(enabled: false); _activeTreePlanesReported = Mathf.Max(0, _activeTreePlanesReported - value.TreeCardCount); _activeCanopyPlanesReported = Mathf.Max(0, _activeCanopyPlanesReported - value.CanopyCardCount); _forestPlanesRemovedThisUpdate += value.TreeCardCount + value.CanopyCardCount; bool flag = _enableForestObjectPooling == null || _enableForestObjectPooling.Value; bool flag2 = _enableForestMemoryCache == null || _enableForestMemoryCache.Value; if (allowCache && flag && flag2) { value.LastUsedRealtime = Time.realtimeSinceStartup; _forestTileCache[key] = value; EvictForestCacheIfOverBudget(); } else { _forestRetirementQueue.Enqueue(value); } } } private void ForgetTreeRendererPropertyStates(ForestTile tile) { if (tile == null) { return; } for (int i = 0; i < tile.Chunks.Count; i++) { ForestChunk forestChunk = tile.Chunks[i]; if ((Object)(object)forestChunk.TreeRenderer != (Object)null) { _treeRendererPropertyStates.Remove(((Object)forestChunk.TreeRenderer).GetInstanceID()); } if ((Object)(object)forestChunk.CanopyRenderer != (Object)null) { _treeRendererPropertyStates.Remove(((Object)forestChunk.CanopyRenderer).GetInstanceID()); } if ((Object)(object)forestChunk.MountainBiomeRenderer != (Object)null) { _treeRendererPropertyStates.Remove(((Object)forestChunk.MountainBiomeRenderer).GetInstanceID()); } if ((Object)(object)forestChunk.SwampBiomeRenderer != (Object)null) { _treeRendererPropertyStates.Remove(((Object)forestChunk.SwampBiomeRenderer).GetInstanceID()); } } } private float EstimateForestCacheMemoryMb() { long num = 0L; foreach (ForestTile value in _forestTileCache.Values) { num += value.EstimatedVertexCount; } return (float)(num * 32) / 1048576f; } private void EvictForestCacheIfOverBudget() { int num = ((_maxCachedForestChunks != null) ? _maxCachedForestChunks.Value : 2048); int num2 = ((_maxPooledForestChunks != null) ? _maxPooledForestChunks.Value : 512); int num3 = Mathf.Min(num, num2); float num4 = ((_forestMemoryCacheLimitMb != null) ? _forestMemoryCacheLimitMb.Value : 256f); int num5 = num3 + 16; while (num5-- > 0 && (_forestTileCache.Count > num3 || EstimateForestCacheMemoryMb() > num4)) { long num6 = 0L; float num7 = float.MaxValue; bool flag = false; foreach (KeyValuePair item2 in _forestTileCache) { if (item2.Value.LastUsedRealtime < num7) { num7 = item2.Value.LastUsedRealtime; num6 = item2.Key; flag = true; } } if (flag) { ForestTile item = _forestTileCache[num6]; _forestTileCache.Remove(num6); DeactivateGroundCardRecordsForTile(num6, deleteRecords: true); _forestRetirementQueue.Enqueue(item); _forestCacheEvictions++; continue; } break; } } private void EvictForestCacheOutsideRetention() { float num = ((_cacheRetentionDistance != null) ? _cacheRetentionDistance.Value : 512f); float num2 = ContinuityTileSize(); float num3 = ((_forestPreloadDistance != null) ? _forestPreloadDistance.Value : 192f); float num4 = ContinuityEnd() + num2 + num3 + num; List list = new List(_forestTileCache.Keys); for (int i = 0; i < list.Count; i++) { ForestTile forestTile = _forestTileCache[list[i]]; float num5 = DistanceToTile(_buildAnchor.x, _buildAnchor.z, forestTile.TileX, forestTile.TileZ, forestTile.Size); if (num5 > num4) { _forestTileCache.Remove(list[i]); DeactivateGroundCardRecordsForTile(list[i], deleteRecords: true); _forestRetirementQueue.Enqueue(forestTile); _forestCacheEvictions++; } } } private string CurrentForestGenerationSignatureBase() { return "4.6.31|" + ((_provider != null) ? _provider.WorldIdentity : "none") + "|" + ClusterCellSize().ToString("F1", CultureInfo.InvariantCulture) + "|" + ForestDensityMultiplier().ToString("F3", CultureInfo.InvariantCulture) + "|" + ForestDensityThreshold().ToString("F5", CultureInfo.InvariantCulture) + "|" + MixedCandidateDensityFloor().ToString("F3", CultureInfo.InvariantCulture) + "|" + SwampCandidateDensityFloor().ToString("F3", CultureInfo.InvariantCulture) + "|" + MountainCandidateDensityFloor().ToString("F3", CultureInfo.InvariantCulture) + "|" + PlainsCandidateDensityFloor().ToString("F3", CultureInfo.InvariantCulture) + "|" + ((_treeAtlasFile != null) ? _treeAtlasFile.Value : "") + "|" + ((_canopyAtlasFile != null) ? _canopyAtlasFile.Value : "") + "|" + ((_mountainBiomeAtlasFile != null) ? _mountainBiomeAtlasFile.Value : "") + "|" + ((_swampBiomeAtlasFile != null) ? _swampBiomeAtlasFile.Value : "") + "|" + BoundaryTreelineChunkSize().ToString("F1", CultureInfo.InvariantCulture) + "|" + NormalForestChunkSize().ToString("F1", CultureInfo.InvariantCulture) + "|density" + CurrentBiomeDensitySignature().ToString("F4", CultureInfo.InvariantCulture) + "|swampembed" + ((_finalRootEmbedDepth != null) ? _finalRootEmbedDepth.Value : 0f).ToString("F2", CultureInfo.InvariantCulture) + "|handofffill" + HandoffFillEnabled() + "_" + HandoffFillBandWidth().ToString("F0", CultureInfo.InvariantCulture) + "_" + HandoffFillMaximumGap().ToString("F0", CultureInfo.InvariantCulture) + "_" + (_handoffFillUsesBiomeDensity != null && _handoffFillUsesBiomeDensity.Value) + "_" + (_handoffFillRequiresValidForestLand != null && _handoffFillRequiresValidForestLand.Value) + "|continuous=" + ContinuousForestCoverageEnabled() + "_" + ContinuousCoverageTargetForBiome((Biome)1).ToString("R", CultureInfo.InvariantCulture) + "_" + ContinuousCoverageTargetForBiome((Biome)8).ToString("R", CultureInfo.InvariantCulture) + "_" + ContinuousCoverageTargetForBiome((Biome)2).ToString("R", CultureInfo.InvariantCulture) + "_" + ContinuousCoverageTargetForBiome((Biome)4).ToString("R", CultureInfo.InvariantCulture) + "_" + ContinuousCoverageTargetForBiome((Biome)16).ToString("R", CultureInfo.InvariantCulture) + "_" + ContinuousCoverageGridRetention(ForestRing.Near).ToString("R", CultureInfo.InvariantCulture) + "_" + ContinuousCoverageGridRetention(ForestRing.Mid).ToString("R", CultureInfo.InvariantCulture) + "_" + ContinuousCoverageGridRetention(ForestRing.Far).ToString("R", CultureInfo.InvariantCulture) + "_" + ContinuousCoverageGridRetention(ForestRing.Horizon).ToString("R", CultureInfo.InvariantCulture) + "|coastalRecovery=" + (_enableCoastalLandRecovery != null && _enableCoastalLandRecovery.Value) + "_" + ((_coastalLandRecoveryRadius != null) ? _coastalLandRecoveryRadius.Value : 48f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_coastalLandRecoveryAttempts != null) ? _coastalLandRecoveryAttempts.Value : 36) + "_" + ((_blackForestNearMinimumSubclusters != null) ? _blackForestNearMinimumSubclusters.Value : 3) + "_" + ((_meadowsNearMinimumSubclusters != null) ? _meadowsNearMinimumSubclusters.Value : 2) + "_" + (_allowDetailedTreeFoliageOverhangAtCoast != null && _allowDetailedTreeFoliageOverhangAtCoast.Value) + "_" + ((_coastalDetailedTreeWaterSafetyWidth != null) ? _coastalDetailedTreeWaterSafetyWidth.Value : 3.5f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_coastalDetailedTreeNearWaterRejectRadius != null) ? _coastalDetailedTreeNearWaterRejectRadius.Value : 2.5f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_coastalDetailedTreeMinimumAboveWater != null) ? _coastalDetailedTreeMinimumAboveWater.Value : 0.2f).ToString("R", CultureInfo.InvariantCulture) + "|terrainColour=" + (_useFullResolutionProviderTerrainColour != null && _useFullResolutionProviderTerrainColour.Value) + "_" + (_useUntintedProviderTerrainColourMap != null && _useUntintedProviderTerrainColourMap.Value) + "_" + ((_fallbackTerrainColourTextureResolution != null) ? _fallbackTerrainColourTextureResolution.Value : 64) + "|neutralAtlasNormals=" + (_useNeutralAtlasNormals == null || _useNeutralAtlasNormals.Value) + "|tileSize=" + ContinuityTileSize().ToString("R", CultureInfo.InvariantCulture) + "|farBatch=" + (_forestFarChunkMergeEnabled != null && _forestFarChunkMergeEnabled.Value) + "_" + ((_midForestChunkSize != null) ? _midForestChunkSize.Value : 96f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_forestFarChunkSize != null) ? _forestFarChunkSize.Value : 128f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_forestFarChunkMergeStart != null) ? _forestFarChunkMergeStart.Value : 2500f).ToString("R", CultureInfo.InvariantCulture) + "_" + (_forestVeryFarChunkMergeEnabled != null && _forestVeryFarChunkMergeEnabled.Value) + "_" + ((_forestVeryFarChunkSize != null) ? _forestVeryFarChunkSize.Value : 160f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_forestVeryFarChunkMergeStart != null) ? _forestVeryFarChunkMergeStart.Value : 6000f).ToString("R", CultureInfo.InvariantCulture) + "|farLod=" + (_enableFarSinglePlaneLod != null && _enableFarSinglePlaneLod.Value) + "_" + ((_farSinglePlaneLodStartDistance != null) ? _farSinglePlaneLodStartDistance.Value : 1400f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_horizonSinglePlaneLodStartDistance != null) ? _horizonSinglePlaneLodStartDistance.Value : 2600f).ToString("R", CultureInfo.InvariantCulture) + "|viewGuard=" + (_enableViewFacingForestOverloadGuard != null && _enableViewFacingForestOverloadGuard.Value) + "_" + ((_visibleDetailedTriangleSoftLimit != null) ? _visibleDetailedTriangleSoftLimit.Value : 220000) + "_" + ((_visibleDetailedTriangleHardLimit != null) ? _visibleDetailedTriangleHardLimit.Value : 320000) + "_" + ((_visibleTreeRendererSoftLimit != null) ? _visibleTreeRendererSoftLimit.Value : 450) + "_" + ((_visibleTreeRendererHardLimit != null) ? _visibleTreeRendererHardLimit.Value : 650) + "|seamOverlap=" + NativeTreelineSeamOverlap().ToString("R", CultureInfo.InvariantCulture) + "|canopyOffset=" + CanopyHandoffOffset().ToString("R", CultureInfo.InvariantCulture) + "|contract=" + 5 + "." + 5 + "." + 6 + "." + 10 + "." + 3 + "." + 13 + "." + 10 + "." + 2 + "." + 1 + "." + 10 + "." + 2 + "." + 5 + "." + 6 + "." + 1 + "." + 2 + "." + 3 + "." + 2 + "." + 1 + "." + 2 + "." + 4 + "." + 2 + "." + 4 + "." + 1 + "|candidateCap=" + EffectiveMaximumCandidateCellsPerTileBuild() + "|H=" + NativeTreelineHandoff().ToString("R", CultureInfo.InvariantCulture) + "|TreeStart=" + ContinuityStart().ToString("R", CultureInfo.InvariantCulture) + "|ground=" + (_enableStrictFinalHeightmapValidation != null && _enableStrictFinalHeightmapValidation.Value) + "_" + ((_maxFinalGroundFloatingError != null) ? _maxFinalGroundFloatingError.Value : 0.2f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_maxFinalGroundBurialError != null) ? _maxFinalGroundBurialError.Value : 0.6f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_maxGroundHeightVarianceStandardCard != null) ? _maxGroundHeightVarianceStandardCard.Value : 1.5f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_maxGroundHeightVarianceLargeCard != null) ? _maxGroundHeightVarianceLargeCard.Value : 0.75f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_minimumRootSupportRatio != null) ? _minimumRootSupportRatio.Value : 0.8f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_minimumFootprintSupportRatio != null) ? _minimumFootprintSupportRatio.Value : 0.7f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_maximumUnsupportedSpan != null) ? _maximumUnsupportedSpan.Value : 1.5f).ToString("R", CultureInfo.InvariantCulture) + "_" + (_rejectGroundCardsOverOpenWater == null || _rejectGroundCardsOverOpenWater.Value) + "_" + (_splitLargeCardsOnUnevenTerrain == null || _splitLargeCardsOnUnevenTerrain.Value) + "|slopeAware=" + (_enableSlopeAwareCardGrounding == null || _enableSlopeAwareCardGrounding.Value) + "_" + ((_maxVisibleEdgeFloatingError != null) ? _maxVisibleEdgeFloatingError.Value : 0.12f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_maxVisibleEdgeBurialError != null) ? _maxVisibleEdgeBurialError.Value : 1.25f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_maxStandardFootprintVariation != null) ? _maxStandardFootprintVariation.Value : 1.25f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_maxMountainFootprintVariation != null) ? _maxMountainFootprintVariation.Value : 1.75f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_minimumAutomaticWidthScale != null) ? _minimumAutomaticWidthScale.Value : 0.45f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_mountainMinimumAutomaticWidthScale != null) ? _mountainMinimumAutomaticWidthScale.Value : 0.72f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_blackForestMinimumAutomaticWidthScale != null) ? _blackForestMinimumAutomaticWidthScale.Value : 0.78f).ToString("R", CultureInfo.InvariantCulture) + "_" + (_enableAutomaticWidthReduction == null || _enableAutomaticWidthReduction.Value) + "_" + (_enableSlopeCardSplitting == null || _enableSlopeCardSplitting.Value) + "_" + ((_maximumSplitAttempts != null) ? _maximumSplitAttempts.Value : 2) + "|widths=" + ((_maximumStandardGroundCardWidth != null) ? _maximumStandardGroundCardWidth.Value : 12f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_maximumSwampGroundCardWidth != null) ? _maximumSwampGroundCardWidth.Value : 10f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_maximumPlainsGroundCardWidth != null) ? _maximumPlainsGroundCardWidth.Value : 10f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_maximumMountainGroundCardWidth != null) ? _maximumMountainGroundCardWidth.Value : 34f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_maximumBlackForestGroundCardWidth != null) ? _maximumBlackForestGroundCardWidth.Value : 46f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_maximumProxyGroundMassWidth != null) ? _maximumProxyGroundMassWidth.Value : 12f).ToString("R", CultureInfo.InvariantCulture) + "|swamprules=" + ((_minimumSwampBiomeFootprintRatio != null) ? _minimumSwampBiomeFootprintRatio.Value : 0.7f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_minimumSwampRootSupportRatio != null) ? _minimumSwampRootSupportRatio.Value : 0.75f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_minimumSwampFootprintSupportRatio != null) ? _minimumSwampFootprintSupportRatio.Value : 0.65f).ToString("R", CultureInfo.InvariantCulture) + "_" + ((_swampMaxShallowWaterDepth != null) ? _swampMaxShallowWaterDepth.Value : 0.2f).ToString("R", CultureInfo.InvariantCulture) + "|roottrim=" + FloatArraySignature(_treeAtlasVisibleRootBottomTrim) + ":" + FloatArraySignature(_canopyAtlasVisibleRootBottomTrim) + ":" + FloatArraySignature(_mountainAtlasVisibleRootBottomTrim) + ":" + FloatArraySignature(_swampAtlasVisibleRootBottomTrim) + "|alphabounds=" + AtlasBoundsSignature(_treeAtlasVisibleBounds) + ":" + AtlasBoundsSignature(_canopyAtlasVisibleBounds) + ":" + AtlasBoundsSignature(_mountainAtlasVisibleBounds) + ":" + AtlasBoundsSignature(_swampAtlasVisibleBounds) + "|epoch" + _forestGenerationEpoch; } private static string FloatArraySignature(float[] values) { if (values == null || values.Length == 0) { return "none"; } string[] array = new string[values.Length]; for (int i = 0; i < values.Length; i++) { array[i] = values[i].ToString("R", CultureInfo.InvariantCulture); } return string.Join(",", array); } private static string AtlasBoundsSignature(AtlasVisibleBounds[] values) { if (values == null || values.Length == 0) { return "none"; } string[] array = new string[values.Length]; for (int i = 0; i < values.Length; i++) { array[i] = values[i].MinU.ToString("R", CultureInfo.InvariantCulture) + "/" + values[i].MaxU.ToString("R", CultureInfo.InvariantCulture) + "/" + values[i].MinV.ToString("R", CultureInfo.InvariantCulture) + "/" + values[i].MaxV.ToString("R", CultureInfo.InvariantCulture); } return string.Join(",", array); } private float CurrentBiomeDensitySignature() { float num = 0f; float num2 = 1f; float[] array = new float[47] { (_meadowsDistantTreeDensity != null) ? _meadowsDistantTreeDensity.Value : 1.1f, (_blackForestDistantTreeDensity != null) ? _blackForestDistantTreeDensity.Value : 1.4f, (_swampDistantTreeDensity != null) ? _swampDistantTreeDensity.Value : 1.2f, (_mountainDistantTreeDensity != null) ? _mountainDistantTreeDensity.Value : 0.65f, (_plainsDistantTreeDensity != null) ? _plainsDistantTreeDensity.Value : 0.25f, (_mistlandsDistantTreeDensity != null) ? _mistlandsDistantTreeDensity.Value : 0.55f, (_ashlandsDistantTreeDensity != null) ? _ashlandsDistantTreeDensity.Value : 0.2f, (_deepNorthDistantTreeDensity != null) ? _deepNorthDistantTreeDensity.Value : 0.35f, (_meadowsDistantCanopyDensity != null) ? _meadowsDistantCanopyDensity.Value : 1f, (_blackForestDistantCanopyDensity != null) ? _blackForestDistantCanopyDensity.Value : 1.35f, (_swampDistantCanopyDensity != null) ? _swampDistantCanopyDensity.Value : 1.05f, (_mountainDistantCanopyDensity != null) ? _mountainDistantCanopyDensity.Value : 0.45f, (_plainsDistantCanopyDensity != null) ? _plainsDistantCanopyDensity.Value : 0.1f, (_mistlandsDistantCanopyDensity != null) ? _mistlandsDistantCanopyDensity.Value : 0.4f, ((_treeCardVerticalAdjustment != null) ? _treeCardVerticalAdjustment.Value : (-0.2f)) * 10f, ((_mixedVerticalAdjustment != null) ? _mixedVerticalAdjustment.Value : 0f) * 10f, ((_blackForestVerticalAdjustment != null) ? _blackForestVerticalAdjustment.Value : 0f) * 10f, ((_swampVerticalAdjustmentFinal != null) ? _swampVerticalAdjustmentFinal.Value : 0f) * 10f, ((_mountainVerticalAdjustmentFinal != null) ? _mountainVerticalAdjustmentFinal.Value : 0f) * 10f, ((_plainsVerticalAdjustmentFinal != null) ? _plainsVerticalAdjustmentFinal.Value : 0f) * 10f, (_mountainTreeHeightMultiplier != null) ? _mountainTreeHeightMultiplier.Value : 2.75f, (_mountainTreeWidthMultiplier != null) ? _mountainTreeWidthMultiplier.Value : 2.3f, (_mountainMinimumRandomScale != null) ? _mountainMinimumRandomScale.Value : 0.9f, (_mountainMaximumRandomScale != null) ? _mountainMaximumRandomScale.Value : 1.2f, (_mountainMinimumWidthToHeightRatio != null) ? _mountainMinimumWidthToHeightRatio.Value : 0.42f, (_mountainMaximumWidthToHeightRatio != null) ? _mountainMaximumWidthToHeightRatio.Value : 0.72f, (_mountainMinimumAutomaticWidthScale != null) ? _mountainMinimumAutomaticWidthScale.Value : 0.72f, (_maximumMountainGroundCardWidth != null) ? _maximumMountainGroundCardWidth.Value : 34f, (_blackForestTreeHeightMultiplier != null) ? _blackForestTreeHeightMultiplier.Value : 3.8f, (_blackForestTreeWidthMultiplier != null) ? _blackForestTreeWidthMultiplier.Value : 4f, (_blackForestPineHeightMultiplier != null) ? _blackForestPineHeightMultiplier.Value : 1.35f, (_blackForestPineWidthMultiplier != null) ? _blackForestPineWidthMultiplier.Value : 1.12f, (_blackForestPineMinimumRandomScale != null) ? _blackForestPineMinimumRandomScale.Value : 0.95f, (_blackForestPineMaximumRandomScale != null) ? _blackForestPineMaximumRandomScale.Value : 1.2f, (_blackForestMinimumRandomScale != null) ? _blackForestMinimumRandomScale.Value : 0.9f, (_blackForestMaximumRandomScale != null) ? _blackForestMaximumRandomScale.Value : 1.25f, (_blackForestMinimumWidthToHeightRatio != null) ? _blackForestMinimumWidthToHeightRatio.Value : 0.58f, (_blackForestMaximumWidthToHeightRatio != null) ? _blackForestMaximumWidthToHeightRatio.Value : 0.9f, (_maximumBlackForestGroundCardWidth != null) ? _maximumBlackForestGroundCardWidth.Value : 46f, (_blackForestMinimumAutomaticWidthScale != null) ? _blackForestMinimumAutomaticWidthScale.Value : 0.78f, (_globalDistributedTreeDensity != null) ? _globalDistributedTreeDensity.Value : 1.65f, (_blackForestDistributedDensity != null) ? _blackForestDistributedDensity.Value : 2f, (_meadowsDistributedDensity != null) ? _meadowsDistributedDensity.Value : 1.3f, (_mountainDistributedDensity != null) ? _mountainDistributedDensity.Value : 1.15f, (_plainsDistributedDensity != null) ? _plainsDistributedDensity.Value : 0.25f, (_maximumCandidateCellsPerTileBuild != null) ? _maximumCandidateCellsPerTileBuild.Value : 900, (_candidateEvaluationsPerResumableStep != null) ? _candidateEvaluationsPerResumableStep.Value : 48 }; for (int i = 0; i < array.Length; i++) { num += array[i] * num2; num2 += 0.37f; } return num; } private bool ForestTileSignatureMatches(ForestTile tile, float currentDistance) { if (tile.GenerationSignatureBase != CurrentForestGenerationSignatureBase()) { return false; } if (tile.PrimaryPassOnly && RingPrimaryCoverageComplete(RingForDistance(currentDistance))) { return false; } bool flag = currentDistance <= NativeTreelineHandoff() + 128f + ContinuityTileSize(); if (tile.WasBoundaryBandTile != flag) { return false; } if (tile.WasBoundaryBandTile) { float num = NativeTreelineHandoff(); float num2 = NativeTreelineSeamOverlap(); if (Mathf.Abs(tile.BuiltHBucket - num) > 0.5f || Mathf.Abs(tile.BuiltOBucket - num2) > 0.5f) { return false; } } return true; } private bool TryRestoreForestTileFromCache(long key, float currentDistance, out ForestTile tile) { //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) if (!_forestTileCache.TryGetValue(key, out tile) || tile == null) { tile = null; _forestCacheMisses++; return false; } _forestTileCache.Remove(key); if (!ForestTileSignatureMatches(tile, currentDistance)) { DeactivateGroundCardRecordsForTile(key, deleteRecords: true); _forestRetirementQueue.Enqueue(tile); _forestCacheMisses++; tile = null; return false; } tile.ResetForReuse(); ResetForestTileRendererBindings(tile); _forestTiles[key] = tile; ActivateGroundCardRecordsForTile(key); QueueCoverageSectorsForTile(tile, RingForDistance(currentDistance)); _forestCacheHits++; _activeTreePlanesReported += tile.TreeCardCount; _activeCanopyPlanesReported += tile.CanopyCardCount; _forestPlanesAddedThisUpdate += tile.TreeCardCount + tile.CanopyCardCount; bool flag = false; bool flag2 = false; for (int i = 0; i < tile.Chunks.Count; i++) { if ((Object)(object)tile.Chunks[i].SwampBiomeMesh != (Object)null) { flag = true; } if ((Object)(object)tile.Chunks[i].TreeCardMesh != (Object)null || (Object)(object)tile.Chunks[i].MountainBiomeMesh != (Object)null || (Object)(object)tile.Chunks[i].SwampBiomeMesh != (Object)null) { flag2 = true; } } if (flag) { _swampChunksRestoredFromCache++; _swampChunksPoolReused++; } if (flag2) { Vector3 val = (((Object)(object)_root != (Object)null) ? _root.transform.position : Vector3.zero); float num = Vector3.Distance(tile.Root.transform.position, val); if (num > 0.01f) { if (flag) { _swampCacheTransformMismatches++; } ((BaseUnityPlugin)this).Logger.LogWarning((object)("[New Horizons Treelines] GROUND TRANSFORM mismatch on cache restore for tile " + ((Object)tile.Root).name + " -- resetting to the expected root position.")); tile.Root.transform.position = val; if (Vector3.Distance(tile.Root.transform.position, val) > 0.01f) { if (flag) { _swampPoolResetFailures++; } _groundTransformOk = false; _groundTransformDetail = "VIOLATION (unresetable) on cache restore at " + ((Object)tile.Root).name; } else if (_groundTransformOk) { _groundTransformDetail = "OK (transform corrected on restore, tile " + ((Object)tile.Root).name + ")"; } } } return true; } private void ResetForestTileRendererBindings(ForestTile tile) { if (tile == null) { return; } for (int i = 0; i < tile.Chunks.Count; i++) { ForestChunk forestChunk = tile.Chunks[i]; if (forestChunk != null) { forestChunk.MassFilter.sharedMesh = null; forestChunk.TreeFilter.sharedMesh = null; forestChunk.CanopyFilter.sharedMesh = null; forestChunk.MountainBiomeFilter.sharedMesh = null; forestChunk.SwampBiomeFilter.sharedMesh = null; ((Renderer)forestChunk.MassRenderer).sharedMaterial = null; ((Renderer)forestChunk.TreeRenderer).sharedMaterial = null; ((Renderer)forestChunk.CanopyRenderer).sharedMaterial = null; ((Renderer)forestChunk.MountainBiomeRenderer).sharedMaterial = null; ((Renderer)forestChunk.SwampBiomeRenderer).sharedMaterial = null; forestChunk.MassFilter.sharedMesh = forestChunk.MassMesh; forestChunk.TreeFilter.sharedMesh = forestChunk.TreeCardMesh; forestChunk.CanopyFilter.sharedMesh = forestChunk.CanopyMesh; forestChunk.MountainBiomeFilter.sharedMesh = forestChunk.MountainBiomeMesh; forestChunk.SwampBiomeFilter.sharedMesh = forestChunk.SwampBiomeMesh; if ((Object)(object)forestChunk.MassMesh != (Object)null) { ((Renderer)forestChunk.MassRenderer).sharedMaterial = _forestMaterial; } if ((Object)(object)forestChunk.TreeCardMesh != (Object)null) { ((Renderer)forestChunk.TreeRenderer).sharedMaterial = _treeCardMaterial; } if ((Object)(object)forestChunk.CanopyMesh != (Object)null) { ((Renderer)forestChunk.CanopyRenderer).sharedMaterial = _canopyCardMaterial; } if ((Object)(object)forestChunk.MountainBiomeMesh != (Object)null) { ((Renderer)forestChunk.MountainBiomeRenderer).sharedMaterial = _mountainBiomeCardMaterial; } if ((Object)(object)forestChunk.SwampBiomeMesh != (Object)null) { ((Renderer)forestChunk.SwampBiomeRenderer).sharedMaterial = _swampBiomeCardMaterial; } ConfigureRenderer(forestChunk.MassRenderer); ConfigureTreeCardRenderer(forestChunk.TreeRenderer); ConfigureTreeCardRenderer(forestChunk.CanopyRenderer); ConfigureTreeCardRenderer(forestChunk.MountainBiomeRenderer); ConfigureTreeCardRenderer(forestChunk.SwampBiomeRenderer); forestChunk.SetEnabled(enabled: false); forestChunk.RecalculateBounds(); } } } private int ForestCoverageSector(float worldX, float worldZ) { float num = Mathf.Atan2(worldZ - _buildAnchor.z, worldX - _buildAnchor.x); float num2 = (num + MathF.PI) / (MathF.PI * 2f); return Mathf.Clamp(Mathf.FloorToInt(num2 * 16f), 0, 15); } private bool IsValidForestLandSample(float worldX, float worldZ) { //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_0045: Invalid comparison between Unknown and I4 if (_provider == null || !_provider.IsReady) { return true; } if (_provider.TrySample(worldX, worldZ, out var sample) && sample.Valid && !sample.IsWaterOrOcean) { return (sample.Biome & 0x100) == 0; } return false; } private bool TileContainsValidForestLand(TileRequest request, float tileSize) { float num = (float)request.X * tileSize; float num2 = (float)request.Z * tileSize; for (int i = 0; i < 5; i++) { float worldZ = num2 + tileSize * (0.08f + (float)i * 0.21f); for (int j = 0; j < 5; j++) { float worldX = num + tileSize * (0.08f + (float)j * 0.21f); if (IsValidForestLandSample(worldX, worldZ)) { return true; } } } return false; } private List OrderForestRequestsCoverageFirst(List requests, float tileSize, int budget) { Array.Clear(_ringSectorHasValidLand, 0, _ringSectorHasValidLand.Length); Array.Clear(_ringValidLandSectors, 0, _ringValidLandSectors.Length); _primaryCoverageKeys.Clear(); List[,] array = new List[5, 16]; int[,] array2 = new int[5, 16]; bool[,] array3 = new bool[5, 16]; List list = new List(requests.Count); for (int i = 0; i < requests.Count; i++) { TileRequest tileRequest = requests[i]; ForestRing forestRing = RingForDistance(tileRequest.Distance); float worldX = ((float)tileRequest.X + 0.5f) * tileSize; float worldZ = ((float)tileRequest.Z + 0.5f) * tileSize; int num = ForestCoverageSector(worldX, worldZ); if (TileContainsValidForestLand(tileRequest, tileSize)) { tileRequest.IsPrimaryCoverage = true; if (array[(int)forestRing, num] == null) { array[(int)forestRing, num] = new List(); } array[(int)forestRing, num].Add(tileRequest); if (!array3[(int)forestRing, num]) { array3[(int)forestRing, num] = true; _ringSectorHasValidLand[(int)forestRing, num] = true; _ringValidLandSectors[(int)forestRing]++; } } else { list.Add(tileRequest); } } for (int j = 0; j < 5; j++) { for (int k = 0; k < 16; k++) { array[j, k]?.Sort(TileRequest.CompareResidentThenDistance); } } list.Sort(TileRequest.CompareResidentThenDistance); List list2 = new List(Mathf.Min(requests.Count, budget)); bool flag = true; while (list2.Count < budget && flag) { flag = false; for (int l = 0; l < 5; l++) { if (list2.Count >= budget) { break; } for (int m = 0; m < 16; m++) { if (list2.Count >= budget) { break; } List list3 = array[l, m]; if (list3 != null) { int num2 = array2[l, m]; if (num2 < list3.Count) { TileRequest tileRequest2 = list3[num2]; array2[l, m] = num2 + 1; list2.Add(tileRequest2); _primaryCoverageKeys.Add(tileRequest2.Key); flag = true; } } } } } for (int n = 0; n < list.Count; n++) { if (list2.Count >= budget) { break; } list2.Add(list[n]); } return list2; } private List ComputeDesiredForestTileRequests() { float num = ContinuityTileSize(); float num2 = ((_forestPreloadDistance != null) ? _forestPreloadDistance.Value : 192f); float num3 = ContinuityEnd() + num + num2; int budget = (_lastForestBudget = MaxForestTiles()); int num4 = Mathf.FloorToInt((_buildAnchor.x - num3) / num); int num5 = Mathf.FloorToInt((_buildAnchor.x + num3) / num); int num6 = Mathf.FloorToInt((_buildAnchor.z - num3) / num); int num7 = Mathf.FloorToInt((_buildAnchor.z + num3) / num); List list = new List(); for (int i = num6; i <= num7; i++) { for (int j = num4; j <= num5; j++) { float num8 = DistanceToTile(_buildAnchor.x, _buildAnchor.z, j, i, num); if (_forestContinuityEnabled.Value && !(num8 > num3) && !(num8 < Mathf.Max(0f, ContinuityStart() - num)) && TileInsideWorld(j, i, num)) { long key = TileKey(j, i); TileRequest tileRequest = new TileRequest(j, i, num8, key); tileRequest.IsResident = _forestTiles.ContainsKey(key) || _forestAddJobsByKey.ContainsKey(key) || _forestTileCache.ContainsKey(key); list.Add(tileRequest); } } } list.Sort(TileRequest.CompareDistance); _lastForestTileRequests = list.Count; List list2 = OrderForestRequestsCoverageFirst(list, num, budget); _lastForestTileQueued = list2.Count; _lastQueueBudgetStatus = _lastQueueBudgetStatus + " | forest requests " + list.Count + " coverage-first capped to " + list2.Count + "/" + budget + " | primary sectors " + _primaryCoverageKeys.Count + " | panic ceiling " + PanicTileCeiling(); return list2; } private void SyncForestTilesIncremental(string reason) { _forestPlanesAddedThisUpdate = 0; _forestPlanesRemovedThisUpdate = 0; if (_enableIncrementalForestStreaming != null && !_enableIncrementalForestStreaming.Value) { SyncForestTilesLegacyFullTeardown(reason); return; } List list = ComputeDesiredForestTileRequests(); HashSet hashSet = new HashSet(); for (int i = 0; i < list.Count; i++) { hashSet.Add(list[i].Key); } _forestDesiredChunkCount = hashSet.Count; List list2 = new List(_forestTiles.Keys); int num = 0; int num2 = 0; for (int j = 0; j < list2.Count; j++) { if (!hashSet.Contains(list2[j])) { if (_forestTiles.TryGetValue(list2[j], out var value) && value != null && value.IsCoverageRepair && FlatDistance(value.Center.x, value.Center.z, _buildAnchor.x, _buildAnchor.z) >= ContinuityStart() - value.Size && FlatDistance(value.Center.x, value.Center.z, _buildAnchor.x, _buildAnchor.z) <= ContinuityEnd() + value.Size) { num2++; continue; } RetireForestTile(list2[j], value == null || !value.IsCoverageRepair); num++; } } _forestQueuedRemoveCount = num; for (int num3 = _forestAddQueue.Count - 1; num3 >= 0; num3--) { if (!hashSet.Contains(_forestAddQueue[num3].Key)) { _forestAddJobsByKey.Remove(_forestAddQueue[num3].Key); _forestAddQueue.RemoveAt(num3); _forestCancelledObsoleteJobs++; } } EvictForestCacheOutsideRetention(); int num4 = 0; int num5 = 0; int num6 = 0; for (int k = 0; k < list.Count; k++) { TileRequest tileRequest = list[k]; if (_forestTiles.ContainsKey(tileRequest.Key)) { num2++; continue; } if (tileRequest.Key == _forestCurrentlyBuildingTileKey) { num6++; continue; } bool flag = _forestTileCache.ContainsKey(tileRequest.Key); if (flag) { num5++; } if (_forestAddJobsByKey.TryGetValue(tileRequest.Key, out var value2)) { value2.Distance = tileRequest.Distance; value2.IsPrimaryCoverage = tileRequest.IsPrimaryCoverage; num6++; continue; } ForestAddJob forestAddJob = new ForestAddJob(tileRequest.X, tileRequest.Z, tileRequest.Key, tileRequest.Distance, _forestGenerationEpoch, Time.realtimeSinceStartup, tileRequest.IsPrimaryCoverage); _forestAddQueue.Add(forestAddJob); _forestAddJobsByKey[tileRequest.Key] = forestAddJob; if (!flag) { num4++; } } int num7 = CountDuplicateForestJobKeys(); if (num7 > 0) { _forestDuplicateJobsDetected += num7; ((BaseUnityPlugin)this).Logger.LogError((object)("[New Horizons Treelines] DUPLICATE FOREST JOB DETECTED -- " + num7 + " duplicate tile key(s) found in the pending forest queue after sync.")); } _forestQueuedAddCount = num4; _forestRetainedActiveLastSync = num2; _forestRetainedPendingLastSync = num6; _forestRetainedCachedLastSync = num5; _forestRetainedUnchangedCount = num2 + num6 + num5; _lastIncrementalUpdateReason = reason + " (keep active " + num2 + ", keep pending " + num6 + ", keep cached " + num5 + ", add " + num4 + ", remove " + num + ", duplicates " + num7 + ")"; UpdateRingSectorCoverageState(); } private int CountDuplicateForestJobKeys() { if (_forestAddQueue.Count <= 1) { return 0; } HashSet hashSet = new HashSet(); int num = 0; for (int i = 0; i < _forestAddQueue.Count; i++) { if (!hashSet.Add(_forestAddQueue[i].Key)) { num++; } } return num; } private bool TryGetForestTileWorkState(long tileKey, out ForestTileWorkState state) { if (_forestTiles.ContainsKey(tileKey)) { state = ForestTileWorkState.Active; return true; } if (_forestCurrentlyBuildingTileKey == tileKey) { state = ForestTileWorkState.Building; return true; } if (_forestAddJobsByKey.ContainsKey(tileKey)) { state = ForestTileWorkState.Pending; return true; } if (_forestRetirementQueue.Count > 0) { foreach (ForestTile item in _forestRetirementQueue) { if (TileKey(item.TileX, item.TileZ) == tileKey) { state = ForestTileWorkState.Retiring; return true; } } } if (_forestTileCache.ContainsKey(tileKey)) { state = ForestTileWorkState.Cached; return true; } state = ForestTileWorkState.None; return false; } private void SyncForestTilesLegacyFullTeardown(string reason) { List list = new List(_forestTiles.Keys); for (int i = 0; i < list.Count; i++) { RetireForestTile(list[i], allowCache: false); } PurgeForestTileCache(); _forestAddQueue.Clear(); _forestAddJobsByKey.Clear(); List list2 = ComputeDesiredForestTileRequests(); for (int j = 0; j < list2.Count; j++) { TileRequest tileRequest = list2[j]; ForestAddJob forestAddJob = new ForestAddJob(tileRequest.X, tileRequest.Z, tileRequest.Key, tileRequest.Distance, _forestGenerationEpoch, Time.realtimeSinceStartup, tileRequest.IsPrimaryCoverage); _forestAddQueue.Add(forestAddJob); _forestAddJobsByKey[tileRequest.Key] = forestAddJob; } _forestDesiredChunkCount = list2.Count; _forestQueuedAddCount = list2.Count; _forestRetainedUnchangedCount = 0; _forestQueuedRemoveCount = list.Count; _lastIncrementalUpdateReason = reason + " (incremental streaming disabled -- legacy full teardown, " + list2.Count + " tiles requeued)"; UpdateRingSectorCoverageState(); } private float ComputeForestJobPriorityScore(ForestAddJob job) { //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) float num = NativeTreelineHandoff() + 128f + ContinuityTileSize(); float num2 = ((job.Distance <= num) ? 1000000f : 0f); if (job.IsPrimaryCoverage || JobTargetsEmptyValidSector(job)) { num2 += 4000000f; } else if (job.IsReinforcement) { num2 += 250000f; } num2 += (0f - job.Distance) * 10f; if (!job.IsReinforcement) { num2 = RingForDistance(job.Distance) switch { ForestRing.Handoff => num2 + 20000000f, ForestRing.Near => num2 + 15000000f, ForestRing.Mid => num2 + 10000000f, ForestRing.Far => num2 + 6000000f, _ => num2 + 3000000f, }; } float num3 = ContinuityTileSize(); float num4 = ((float)job.X + 0.5f) * num3; float num5 = ((float)job.Z + 0.5f) * num3; float num6 = num4 - _streamingViewOrigin.x; float num7 = num5 - _streamingViewOrigin.z; float num8 = Mathf.Sqrt(num6 * num6 + num7 * num7); if (num8 > 0.0001f) { num6 /= num8; num7 /= num8; float num9 = num6 * _streamingCameraForwardFlat.x + num7 * _streamingCameraForwardFlat.z; float num10 = ((_enablePredictiveStreamingPriority == null || !_enablePredictiveStreamingPriority.Value) ? 2000f : ((_predictiveCameraPriorityStrength != null) ? _predictiveCameraPriorityStrength.Value : 3000f)); num2 += num9 * num10; if (_enablePredictiveStreamingPriority != null && _enablePredictiveStreamingPriority.Value && ((Vector3)(ref _streamingVelocityFlat)).sqrMagnitude > 1f) { Vector3 normalized = ((Vector3)(ref _streamingVelocityFlat)).normalized; float num11 = num6 * normalized.x + num7 * normalized.z; float num12 = ((_predictiveMovementPriorityStrength != null) ? _predictiveMovementPriorityStrength.Value : 5000f); num2 += num11 * num12; } } if (ShouldDeferReinforcementForPerformance(job)) { num2 -= 8000000f; } float num13 = Time.realtimeSinceStartup - job.QueuedAtRealtime; num2 += Mathf.Min(num13 * 50f, 5000f); if (_ringPlaneCountsCache != null) { RingPlaneCounts ringPlaneCounts = _ringPlaneCountsCache[(int)RingForDistance(job.Distance)]; if (ringPlaneCounts.Tree == 0 && ringPlaneCounts.Canopy == 0) { num2 += 500000f; } } return num2; } private int EffectiveMaximumCandidateCellsPerTileBuild() { if (_maximumCandidateCellsPerTileBuild == null) { return 900; } return Mathf.Clamp(_maximumCandidateCellsPerTileBuild.Value, 64, 5000); } private int CandidateEvaluationsPerResumableStep() { if (_candidateEvaluationsPerResumableStep == null) { return 48; } return Mathf.Clamp(_candidateEvaluationsPerResumableStep.Value, 8, 256); } private bool StartupHitchGuardEnabled() { if (_enableStartupHitchGuard != null) { return _enableStartupHitchGuard.Value; } return true; } private float SecondsSinceForestAtlasReady() { if (!(_forestAtlasReadyRealtime < 0f)) { return Mathf.Max(0f, Time.realtimeSinceStartup - _forestAtlasReadyRealtime); } return 0f; } private bool StartupInitialDelayActive() { if (!StartupHitchGuardEnabled() || _forestAtlasReadyRealtime < 0f) { return false; } float num = ((_startupInitialDelaySeconds != null) ? Mathf.Max(0f, _startupInitialDelaySeconds.Value) : 1.5f); return SecondsSinceForestAtlasReady() < num; } private bool StartupHitchGuardActive() { if (!StartupHitchGuardEnabled()) { return false; } if (_forestAtlasReadyRealtime < 0f) { return _hasBuildAnchor; } float num = ((_startupSafeModeSeconds != null) ? Mathf.Max(0f, _startupSafeModeSeconds.Value) : 45f); return SecondsSinceForestAtlasReady() < num; } private bool OptionalForestWorkAllowed() { if (StartupHitchGuardActive()) { return false; } if (AdaptiveHighPresetGovernorActive() && _adaptivePressure >= 0.25f) { return false; } if (_coverageRepairQueue.Count > 0) { return false; } return true; } private bool CoverageRepairAllowedThisFrame() { if (StartupHitchGuardActive()) { return false; } int num = ((_minimumActiveChunksBeforeCoverageRepair != null) ? Mathf.Max(0, _minimumActiveChunksBeforeCoverageRepair.Value) : 24); if (_forestTiles.Count < num) { return false; } float num2 = Time.unscaledDeltaTime * 1000f; float num3 = ((_pauseGenerationAboveFrameTimeMs != null) ? _pauseGenerationAboveFrameTimeMs.Value : 40f); if (num2 > Mathf.Min(num3, 25f)) { return false; } if (ForestGenerationFrameBudgetExpired()) { return false; } return true; } private bool AdaptiveHighPresetGovernorActive() { if (_enableAdaptiveHighPresetGovernor == null || !_enableAdaptiveHighPresetGovernor.Value) { return false; } switch ((_qualityPreset != null) ? _qualityPreset.Value : QualityPreset.Custom) { case QualityPreset.Custom: return ExtensionDistance() >= 7000f; default: return false; case QualityPreset.High: case QualityPreset.Ultra: case QualityPreset.Horizon: return true; } } private void UpdateAdaptivePerformanceGovernor() { float num = Mathf.Clamp(Time.unscaledDeltaTime * 1000f, 1f, 250f); int num2 = ((_adaptiveFrameSmoothingSamples != null) ? Mathf.Clamp(_adaptiveFrameSmoothingSamples.Value, 8, 180) : 45); float num3 = 2f / ((float)num2 + 1f); _adaptiveAverageFrameMs = Mathf.Lerp(_adaptiveAverageFrameMs, num, num3); if (!AdaptiveHighPresetGovernorActive()) { _adaptivePressure = 0f; _adaptiveStableSeconds = 0f; _adaptiveHardSpikeCooldownRemaining = 0f; _adaptiveBuildOverrunCooldownRemaining = 0f; _adaptiveEffectiveGenerationBudgetMs = ((_forestGenerationTimeBudgetMs != null) ? _forestGenerationTimeBudgetMs.Value : 2f); _adaptiveEffectiveMeshUploads = BaseMaximumMeshUploadsPerFrame(); _adaptiveEffectiveChunkActivations = ((_maxChunkActivationsPerFrame != null) ? _maxChunkActivationsPerFrame.Value : 8); _adaptiveEffectiveTilesPerFrame = BaseTilesBuiltPerFrame(); _adaptiveGovernorState = "inactive for current preset"; return; } float num4 = ((_adaptiveTargetFrameTimeMs != null) ? _adaptiveTargetFrameTimeMs.Value : 16.67f); float num5 = Mathf.Max(num4 + 0.5f, (_adaptiveSoftFrameTimeMs != null) ? _adaptiveSoftFrameTimeMs.Value : 22.22f); float num6 = Mathf.Max(num5 + 0.5f, (_adaptiveHardFrameTimeMs != null) ? _adaptiveHardFrameTimeMs.Value : 33.33f); float num7 = ((_adaptiveAverageFrameMs <= num4) ? 0f : Mathf.Clamp01(Mathf.InverseLerp(num4, num6, _adaptiveAverageFrameMs))); if (num >= num6) { _adaptiveHardSpikeCooldownRemaining = Mathf.Max(_adaptiveHardSpikeCooldownRemaining, (_adaptiveHardSpikeCooldownSeconds != null) ? _adaptiveHardSpikeCooldownSeconds.Value : 0.35f); num7 = 1f; } float num8 = Mathf.Max(0f, Time.unscaledDeltaTime); _adaptiveHardSpikeCooldownRemaining = Mathf.Max(0f, _adaptiveHardSpikeCooldownRemaining - num8); _adaptiveBuildOverrunCooldownRemaining = Mathf.Max(0f, _adaptiveBuildOverrunCooldownRemaining - num8); if (num7 > _adaptivePressure) { _adaptivePressure = Mathf.MoveTowards(_adaptivePressure, num7, num8 * 3.5f); _adaptiveStableSeconds = 0f; } else if (_adaptiveAverageFrameMs <= num5 && _adaptiveHardSpikeCooldownRemaining <= 0f && _adaptiveBuildOverrunCooldownRemaining <= 0f) { _adaptiveStableSeconds += num8; float num9 = ((_adaptiveRecoveryDelaySeconds != null) ? _adaptiveRecoveryDelaySeconds.Value : 2f); if (_adaptiveStableSeconds >= num9) { float num10 = ((_adaptiveRecoveryRatePerSecond != null) ? _adaptiveRecoveryRatePerSecond.Value : 0.12f); _adaptivePressure = Mathf.MoveTowards(_adaptivePressure, num7, num8 * num10); } } else { _adaptiveStableSeconds = 0f; } if (_adaptiveHardSpikeCooldownRemaining > 0f || _adaptiveBuildOverrunCooldownRemaining > 0f) { _adaptivePressure = Mathf.Max(_adaptivePressure, 0.9f); } float num11 = ((_forestGenerationTimeBudgetMs != null) ? _forestGenerationTimeBudgetMs.Value : 2f); float num12 = ((_adaptiveMinimumGenerationBudgetMs != null) ? _adaptiveMinimumGenerationBudgetMs.Value : 0.2f); _adaptiveEffectiveGenerationBudgetMs = Mathf.Lerp(num11, Mathf.Min(num11, num12), _adaptivePressure); int num13 = BaseMaximumMeshUploadsPerFrame(); int num14 = ((_adaptiveMinimumMeshUploadsPerFrame == null) ? 1 : _adaptiveMinimumMeshUploadsPerFrame.Value); _adaptiveEffectiveMeshUploads = Mathf.Clamp(Mathf.RoundToInt(Mathf.Lerp((float)num13, (float)num14, _adaptivePressure)), 1, num13); int num15 = ((_maxChunkActivationsPerFrame != null) ? _maxChunkActivationsPerFrame.Value : 8); int num16 = ((_adaptiveMinimumChunkActivationsPerFrame != null) ? _adaptiveMinimumChunkActivationsPerFrame.Value : 2); _adaptiveEffectiveChunkActivations = Mathf.Clamp(Mathf.RoundToInt(Mathf.Lerp((float)num15, (float)num16, _adaptivePressure)), 1, num15); int num17 = BaseTilesBuiltPerFrame(); _adaptiveEffectiveTilesPerFrame = Mathf.Clamp(Mathf.RoundToInt(Mathf.Lerp((float)num17, 1f, _adaptivePressure)), 1, num17); if (_adaptiveHardSpikeCooldownRemaining > 0f) { _adaptiveGovernorState = "hard-spike cooldown"; } else if (_adaptiveBuildOverrunCooldownRemaining > 0f) { _adaptiveGovernorState = "tile-overrun cooldown"; } else if (_adaptivePressure >= 0.75f) { _adaptiveGovernorState = "heavy throttle"; } else if (_adaptivePressure >= 0.3f) { _adaptiveGovernorState = "moderate throttle"; } else if (_adaptivePressure > 0.02f) { _adaptiveGovernorState = "light throttle"; } else { _adaptiveGovernorState = "full workload"; } } private float EffectiveForestGenerationBudgetMs() { if (_enableAdaptiveForestGenerationBudget != null && _enableAdaptiveForestGenerationBudget.Value) { return CurrentForestGenerationCpuBudgetMs(); } if (!AdaptiveHighPresetGovernorActive()) { if (_forestGenerationTimeBudgetMs == null) { return 2f; } return _forestGenerationTimeBudgetMs.Value; } return Mathf.Max(0.05f, _adaptiveEffectiveGenerationBudgetMs); } private void UpdateForestGenerationPressureMode() { float num = Time.unscaledDeltaTime * 1000f; float num2 = ((_generationTargetFrameTimeMs != null) ? _generationTargetFrameTimeMs.Value : 16.67f); if (num > 22f) { _forestPressureSlowFrameStreak++; } else { _forestPressureSlowFrameStreak = 0; } bool flag = ((Vector3)(ref _streamingVelocityFlat)).magnitude > 7f || _forestCameraAngularSpeed > 90f || _forestTeleportPressureThisFrame; bool flag2 = _forestGenerationTimeThisFrameMs > Mathf.Max(0.1f, _forestCurrentCpuBudgetMs) || _forestMeshUploadTimeThisFrameMs > 2f; _forestFrameTimePressure = num > num2; bool flag3 = _forestPressureSlowFrameStreak >= 3 || flag || flag2 || AdaptiveGenerationCoolingDown(); float num3 = Mathf.Max(0f, Time.unscaledDeltaTime); if (flag3) { _forestGenerationPressureMode = true; _forestGenerationPressureRecoveryRemaining = ((_generationBudgetRecoveryDelaySeconds != null) ? Mathf.Max(0.1f, _generationBudgetRecoveryDelaySeconds.Value) : 1f); } else if (_forestGenerationPressureMode) { _forestGenerationPressureRecoveryRemaining -= num3; if (_forestGenerationPressureRecoveryRemaining <= 0f) { _forestGenerationPressureMode = false; } } if (_showDebug != null && _showDebug.Value) { long totalMemory = GC.GetTotalMemory(forceFullCollection: false); if (_forestGcSecondStartedRealtime <= 0f) { _forestGcSecondStartedRealtime = Time.realtimeSinceStartup; _forestGcBytesAtSecondStart = totalMemory; } else if (Time.realtimeSinceStartup - _forestGcSecondStartedRealtime >= 1f) { _forestGcAllocationsThisSecond = Math.Max(0L, totalMemory - _forestGcBytesAtSecondStart); _forestGcBytesAtSecondStart = totalMemory; _forestGcSecondStartedRealtime = Time.realtimeSinceStartup; } } } private float CurrentForestGenerationCpuBudgetMs() { if (_enableAdaptiveForestGenerationBudget == null || !_enableAdaptiveForestGenerationBudget.Value) { if (_forestGenerationTimeBudgetMs == null) { return 2f; } return _forestGenerationTimeBudgetMs.Value; } if (StartupHitchGuardActive()) { if (_startupForestGenerationCpuBudgetMs == null) { return 0.5f; } return _startupForestGenerationCpuBudgetMs.Value; } if (_forestGenerationPressureMode || _forestFrameTimePressure) { if (_movementPressureForestGenerationCpuBudgetMs == null) { return 0.4f; } return _movementPressureForestGenerationCpuBudgetMs.Value; } if (((Vector3)(ref _streamingVelocityFlat)).magnitude < 0.25f && _forestCameraAngularSpeed < 8f) { if (_stationaryForestGenerationCpuBudgetMs == null) { return 1.5f; } return _stationaryForestGenerationCpuBudgetMs.Value; } if (_normalForestGenerationCpuBudgetMs == null) { return 1f; } return _normalForestGenerationCpuBudgetMs.Value; } private bool ForestGenerationFrameBudgetExpired() { if (_forestFrameBudgetStopwatch != null) { return _forestFrameBudgetStopwatch.Elapsed.TotalMilliseconds >= (double)_forestCurrentCpuBudgetMs; } return false; } private int EffectiveMaximumChunkActivationsPerFrame() { int num = (AdaptiveHighPresetGovernorActive() ? Mathf.Max(1, _adaptiveEffectiveChunkActivations) : ((_maxChunkActivationsPerFrame != null) ? _maxChunkActivationsPerFrame.Value : 8)); return Mathf.Min(1, num); } private bool AdaptiveGenerationCoolingDown() { if (AdaptiveHighPresetGovernorActive()) { if (!(_adaptiveHardSpikeCooldownRemaining > 0f)) { return _adaptiveBuildOverrunCooldownRemaining > 0f; } return true; } return false; } private bool ShouldDeferReinforcementForPerformance(ForestAddJob job) { if (job == null || !job.IsReinforcement || !AdaptiveHighPresetGovernorActive()) { return false; } float num = ((_adaptiveReinforcementDeferPressure != null) ? _adaptiveReinforcementDeferPressure.Value : 0.35f); return _adaptivePressure >= num; } private bool ForestAtlasMaterialsReady() { if ((Object)(object)_treeCardMaterial != (Object)null) { return _treeCardCutoutMaterialValid; } return false; } private int SumRingVisibleChunks() { int num = 0; for (int i = 0; i < 5; i++) { num += _ringVisibleChunkCounts[i]; } return num; } private int HandoffActiveTileCount() { int num = 0; foreach (ForestTile value in _forestTiles.Values) { if (value != null) { float distance = FlatDistance(_buildAnchor.x, _buildAnchor.z, value.Center.x, value.Center.z); if (RingForDistance(distance) == ForestRing.Handoff) { num++; } } } return num; } private int HandoffPendingGenerationCount() { int num = 0; for (int i = 0; i < _forestAddQueue.Count; i++) { if (RingForDistance(_forestAddQueue[i].Distance) == ForestRing.Handoff) { num++; } } return num; } private string BuildHandoffDiagnosticsLine1() { int num = HandoffActiveTileCount(); int num2 = HandoffPendingGenerationCount(); long num3 = Mathf.Max(0, (int)(_ringValidCellsScanned[0] - _ringCoveredCellsScanned[0])); return "Handoff active tiles: " + num + " | Pending generation: " + num2 + " | Pending uploads: " + Mathf.Min(num2, MaximumMeshUploadsPerFrame()) + " | Uncovered cells (scanned): " + num3; } private string BuildHandoffDiagnosticsLine2() { return "Handoff largest current gap: " + _ringLargestObservedCoverageGap[0].ToString("F0", CultureInfo.InvariantCulture) + "m / limit " + RingMaximumCoverageGap(ForestRing.Handoff).ToString("F0", CultureInfo.InvariantCulture) + "m | Repair jobs pending: " + _ringRepairJobsPending[0] + " | Repairs accepted: " + _ringRepairsAccepted[0] + " | Time since last primary progress: " + (Time.realtimeSinceStartup - _lastPrimaryProgressRealtime).ToString("F1", CultureInfo.InvariantCulture) + "s"; } private bool HandoffActiveCoverageOk() { if (!ForestAtlasMaterialsReady()) { return false; } if (HandoffActiveTileCount() == 0) { return false; } if (HandoffPendingGenerationCount() > 0) { return false; } if (_ringRepairJobsPending[0] > 0) { return false; } return true; } private void ProcessForestStreaming() { if (!ForestAtlasMaterialsReady()) { if (!_forestAtlasBarrierActive) { _forestAtlasBarrierActive = true; _forestAtlasBarrierEverActive = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[New Horizons Treelines] FOREST ATLAS BARRIER ACTIVE -- forest tile generation paused, " + _forestAddQueue.Count + " job(s) remain queued (not built, not marked complete) until the tree atlas material is ready.")); } return; } if (_forestAtlasReadyRealtime < 0f) { _forestAtlasReadyRealtime = Time.realtimeSinceStartup; _startupForestBuildFrameCounter = 0; _startupTerrainBuildFrameCounter = 0; } if (_forestAtlasBarrierActive) { _forestAtlasBarrierActive = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[New Horizons Treelines] FOREST GENERATION RESUMED -- validated atlas materials passed the startup hitch guard."); } _forestChunksBuiltThisFrame = 0; _forestMeshesUploadedThisFrame = 0; _forestGenerationTimeThisFrameMs = 0f; _forestMeshUploadTimeThisFrameMs = 0f; _forestCacheActivationsThisFrame = 0; _forestCacheActivationsDeferredThisFrame = 0; _reinforcementJobsDeferredThisFrame = 0; _forestCandidatesProcessedThisFrame = 0; _forestGroundingSamplesThisFrame = 0; _forestMeshVerticesThisFrame = 0; if (_activeForestBuild != null) { _forestActiveResumableJobs = 1; return; } if (StartupInitialDelayActive()) { _startupForestFramesDeferred++; _cardsBlockedByBootstrapSafety++; _forestCurrentJobStage = "startup settle delay"; return; } if (StartupHitchGuardActive()) { int num = ((_startupForestBuildIntervalFrames != null) ? Mathf.Clamp(_startupForestBuildIntervalFrames.Value, 1, 12) : 2); _startupForestBuildFrameCounter++; if (_startupForestBuildFrameCounter < num) { _startupForestFramesDeferred++; _cardsBlockedByBootstrapSafety++; _forestCurrentJobStage = "startup stagger"; return; } _startupForestBuildFrameCounter = 0; } int num2 = 0; for (int i = 0; i < 5; i++) { num2 += _ringVisibleChunkCounts[i]; } float num3 = Time.realtimeSinceStartup - _lastPrimaryProgressRealtime; float num4 = ((_maximumPrimaryStarvationSeconds != null) ? _maximumPrimaryStarvationSeconds.Value : 1f); bool flag = (_forestBootstrapActiveLastFrame = num2 == 0 || num3 > num4); float num5 = Time.unscaledDeltaTime * 1000f; float num6 = ((_pauseGenerationAboveFrameTimeMs != null) ? _pauseGenerationAboveFrameTimeMs.Value : 40f); bool flag2 = num5 > num6 || AdaptiveGenerationCoolingDown(); if (flag2 && !flag) { _forestPausedPreviousFrame = true; return; } float num7 = (_forestPausedPreviousFrame ? Mathf.Min(EffectiveForestGenerationBudgetMs(), (_slowFrameGenerationBudgetMs != null) ? _slowFrameGenerationBudgetMs.Value : 0.5f) : EffectiveForestGenerationBudgetMs()); int num8 = MaximumMeshUploadsPerFrame(); if (flag2 && flag) { num7 = Mathf.Max(num7, (_bootstrapPrimaryGenerationBudgetMs != null) ? _bootstrapPrimaryGenerationBudgetMs.Value : 0.75f); num8 = Mathf.Max(num8, (_bootstrapMeshUploadsPerFrame == null) ? 1 : _bootstrapMeshUploadsPerFrame.Value); } _forestPausedPreviousFrame = false; int num9 = EffectiveMaximumChunkActivationsPerFrame(); int num10 = ((_maximumForestTileBuildsPerFrameSafetyCap == null) ? 1 : Mathf.Clamp(_maximumForestTileBuildsPerFrameSafetyCap.Value, 1, 2)); int num11 = Mathf.Min(Mathf.Max(1, TilesBuiltPerFrame()), num10); if (StartupHitchGuardActive()) { num11 = 1; num8 = Mathf.Min(num8, 1); num9 = Mathf.Min(num9, 1); } int num12 = (flag ? ((_minimumPrimaryProgressStepsPerFrame == null) ? 1 : Mathf.Clamp(_minimumPrimaryProgressStepsPerFrame.Value, 1, 4)) : 0); int num13 = 0; Stopwatch stopwatch = Stopwatch.StartNew(); int num14 = 0; int num15 = 0; int num16 = 0; _ringPlaneCountsCache = ComputeRingPlaneCounts(); _currentBudgetStarvationDetected = false; UpdateRingSectorCoverageState(); if (OptionalForestWorkAllowed()) { QueueCoverageReinforcementJobs(); } if (!ActiveBudgetAccountingOk(out var treeDiff, out var canopyDiff)) { _activeTreePlanesReported = CountTreeCards(); _activeCanopyPlanesReported = CountCanopyCards(); _budgetReconciliationCorrections++; if (Time.realtimeSinceStartup - _lastBudgetAccountingWarningRealtime >= 5f) { _lastBudgetAccountingWarningRealtime = Time.realtimeSinceStartup; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[New Horizons Treelines] ACTIVE BUDGET ACCOUNTING VIOLATION detected and corrected (tree diff " + treeDiff + ", canopy diff " + canopyDiff + ").")); } } while (_forestAddQueue.Count > 0 && num16 < num11 && ((stopwatch.Elapsed.TotalMilliseconds < (double)num7 && num14 < num8) || num13 < num12)) { int num17 = -1; float num18 = float.NegativeInfinity; for (int j = 0; j < _forestAddQueue.Count; j++) { ForestAddJob forestAddJob = _forestAddQueue[j]; if (forestAddJob.Epoch != _forestGenerationEpoch) { continue; } if (num15 >= num9 && _forestTileCache.ContainsKey(forestAddJob.Key)) { _forestCacheActivationsDeferredThisFrame++; _forestDeferredUploadsTotal++; continue; } if (ShouldDeferReinforcementForPerformance(forestAddJob)) { _reinforcementJobsDeferredThisFrame++; _cardsBlockedByReinforcementCap++; continue; } float num19 = ComputeForestJobPriorityScore(forestAddJob); if (num19 > num18) { num18 = num19; num17 = j; } } if (num17 < 0) { for (int num20 = _forestAddQueue.Count - 1; num20 >= 0; num20--) { if (_forestAddQueue[num20].Epoch != _forestGenerationEpoch) { _forestAddJobsByKey.Remove(_forestAddQueue[num20].Key); _forestAddQueue.RemoveAt(num20); _forestCancelledObsoleteJobs++; _forestCancelledJobsTotal++; } } break; } ForestAddJob forestAddJob2 = _forestAddQueue[num17]; _forestAddQueue.RemoveAt(num17); _forestAddJobsByKey.Remove(forestAddJob2.Key); if (_forestTiles.ContainsKey(forestAddJob2.Key) && !forestAddJob2.IsReinforcement) { continue; } if (!forestAddJob2.IsReinforcement && _forestTileCache.ContainsKey(forestAddJob2.Key) && TryRestoreForestTileFromCache(forestAddJob2.Key, forestAddJob2.Distance, out var _)) { num15++; _forestCacheActivationsThisFrame++; _forestChunkActivationsThisFrame++; num16++; UpdateRingSectorCoverageState(); continue; } if (forestAddJob2.IsReinforcement && _forestTiles.ContainsKey(forestAddJob2.Key)) { RetireForestTile(forestAddJob2.Key, allowCache: false); _ringPlaneCountsCache = ComputeRingPlaneCounts(); } ForestRing forestRing = (_lastBuiltTileRing = RingForDistance(forestAddJob2.Distance)); _remainingTreeCardPlaneBudget = ComputeRingAwareTreeBudget(forestRing, _ringPlaneCountsCache); _remainingCanopyPlaneBudget = ComputeRingAwareCanopyBudget(forestRing, _ringPlaneCountsCache); if (_remainingTreeCardPlaneBudget <= 0 && _remainingCanopyPlaneBudget <= 0) { _currentBudgetStarvationDetected = true; _currentBudgetStarvationRing = forestRing; _cardsBlockedByRingReservation++; } _buildingReinforcementJob = forestAddJob2.IsReinforcement; _buildingPrimaryCoverageJob = !forestAddJob2.IsReinforcement && (forestAddJob2.IsPrimaryCoverage || JobTargetsEmptyValidSector(forestAddJob2)); _forestActiveResumableJobs = 1; _forestCurrentJobStage = "candidate generation " + forestAddJob2.X + "," + forestAddJob2.Z; _forestCurrentlyBuildingTileKey = forestAddJob2.Key; ((MonoBehaviour)this).StartCoroutine(BuildForestTileJobResumable(forestAddJob2, forestRing)); break; } stopwatch.Stop(); _forestGenerationTimeThisFrameMs = (float)stopwatch.Elapsed.TotalMilliseconds; UpdateRingSectorCoverageState(); if (OptionalForestWorkAllowed()) { QueueCoverageReinforcementJobs(); } TryReportPostMeshGroundingEpochCompletion(); } private void ProcessForestRetirement() { _forestChunksRetiredThisFrame = 0; _forestRetirementTimeThisFrameMs = 0f; if (_forestRetirementQueue.Count != 0) { float num = ((_forestRetirementTimeBudgetMs != null) ? _forestRetirementTimeBudgetMs.Value : 1f); int num2 = ((_maxChunkDestructionsPerFrame != null) ? _maxChunkDestructionsPerFrame.Value : 4); if (AdaptiveHighPresetGovernorActive()) { num = Mathf.Lerp(num, Mathf.Min(0.25f, num), _adaptivePressure); num2 = Mathf.Max(1, Mathf.RoundToInt(Mathf.Lerp((float)num2, 1f, _adaptivePressure))); } Stopwatch stopwatch = Stopwatch.StartNew(); int num3 = 0; while (_forestRetirementQueue.Count > 0 && num3 < num2 && stopwatch.Elapsed.TotalMilliseconds < (double)num) { ForestTile forestTile = _forestRetirementQueue.Dequeue(); forestTile.Destroy(); num3++; _forestChunksRetiredThisFrame++; } stopwatch.Stop(); _forestRetirementTimeThisFrameMs = (float)stopwatch.Elapsed.TotalMilliseconds; } } private void ProcessTerrainQueue() { if (StartupHitchGuardActive()) { int num = ((_startupTerrainBuildIntervalFrames != null) ? Mathf.Clamp(_startupTerrainBuildIntervalFrames.Value, 1, 30) : 6); _startupTerrainBuildFrameCounter++; if (_startupTerrainBuildFrameCounter < num) { if (_terrainQueue.Count > 0) { _startupTerrainFramesDeferred++; _terrainBuildFramesDeferredForPerformance++; } return; } _startupTerrainBuildFrameCounter = 0; } if (AdaptiveHighPresetGovernorActive() && (AdaptiveGenerationCoolingDown() || _adaptivePressure >= 0.75f)) { if (_terrainQueue.Count > 0) { _terrainBuildFramesDeferredForPerformance++; } return; } int num2 = (AdaptiveHighPresetGovernorActive() ? 1 : TilesBuiltPerFrame()); while (num2 > 0 && _terrainQueue.Count > 0) { TileRequest tileRequest = _terrainQueue.Dequeue(); _terrainQueuedKeys.Remove(tileRequest.Key); if (!_terrainTiles.ContainsKey(tileRequest.Key)) { TerrainTile terrainTile = BuildTerrainTile(tileRequest.X, tileRequest.Z); if (terrainTile != null) { _terrainTiles[tileRequest.Key] = terrainTile; } } num2--; } } private void QueueTerrainTiles() { if (!_enableFarTerrain.Value) { _lastTerrainBudget = 0; _lastTerrainTileRequests = 0; _lastTerrainTileQueued = 0; return; } float num = FarTerrainTileSize(); float num2 = FarTerrainViewDistance(); float num3 = num2 + num; int num4 = (_lastTerrainBudget = MaxTerrainTiles()); float num5 = num / (float)Mathf.Max(1, FarTerrainMeshResolution()); float num6 = VisualExclusionRadius() + num5 * 1.42f; int num7 = Mathf.FloorToInt((_buildAnchor.x - num3) / num); int num8 = Mathf.FloorToInt((_buildAnchor.x + num3) / num); int num9 = Mathf.FloorToInt((_buildAnchor.z - num3) / num); int num10 = Mathf.FloorToInt((_buildAnchor.z + num3) / num); List list = new List(); for (int i = num9; i <= num10; i++) { for (int j = num7; j <= num8; j++) { float num11 = DistanceToTile(_buildAnchor.x, _buildAnchor.z, j, i, num); if (!(num11 > num2 + num) && !(num11 < num6) && TileInsideWorld(j, i, num)) { list.Add(new TileRequest(j, i, num11, TileKey(j, i))); } } } list.Sort(TileRequest.CompareDistance); _lastTerrainTileRequests = list.Count; int num12 = (_lastTerrainTileQueued = Mathf.Min(list.Count, num4)); for (int k = 0; k < num12; k++) { TileRequest tileRequest = list[k]; _terrainQueue.Enqueue(tileRequest); _terrainQueuedKeys.Add(tileRequest.Key); } _lastQueueBudgetStatus = "terrain requests " + list.Count + " capped to " + num12 + "/" + num4; } private void SyncTerrainTilesIncremental(string reason) { if (!_enableFarTerrain.Value) { _lastTerrainBudget = 0; _lastTerrainTileRequests = 0; _lastTerrainTileQueued = 0; return; } float num = FarTerrainTileSize(); float num2 = FarTerrainViewDistance(); float num3 = num2 + num; int num4 = (_lastTerrainBudget = MaxTerrainTiles()); float num5 = num / (float)Mathf.Max(1, FarTerrainMeshResolution()); float num6 = VisualExclusionRadius() + num5 * 1.42f; int num7 = Mathf.FloorToInt((_buildAnchor.x - num3) / num); int num8 = Mathf.FloorToInt((_buildAnchor.x + num3) / num); int num9 = Mathf.FloorToInt((_buildAnchor.z - num3) / num); int num10 = Mathf.FloorToInt((_buildAnchor.z + num3) / num); List list = new List(); for (int i = num9; i <= num10; i++) { for (int j = num7; j <= num8; j++) { float num11 = DistanceToTile(_buildAnchor.x, _buildAnchor.z, j, i, num); if (!(num11 > num2 + num) && !(num11 < num6) && TileInsideWorld(j, i, num)) { list.Add(new TileRequest(j, i, num11, TileKey(j, i))); } } } list.Sort(TileRequest.CompareDistance); _lastTerrainTileRequests = list.Count; int num12 = Mathf.Min(list.Count, num4); HashSet hashSet = new HashSet(); for (int k = 0; k < num12; k++) { hashSet.Add(list[k].Key); } List list2 = new List(_terrainTiles.Keys); int num13 = 0; for (int l = 0; l < list2.Count; l++) { if (!hashSet.Contains(list2[l])) { _terrainTiles[list2[l]].Destroy(); _terrainTiles.Remove(list2[l]); num13++; } } if (_terrainQueue.Count > 0) { int count = _terrainQueue.Count; List list3 = new List(count); for (int m = 0; m < count; m++) { TileRequest tileRequest = _terrainQueue.Dequeue(); if (hashSet.Contains(tileRequest.Key) && !_terrainTiles.ContainsKey(tileRequest.Key)) { list3.Add(tileRequest); } else { _terrainQueuedKeys.Remove(tileRequest.Key); } } for (int n = 0; n < list3.Count; n++) { _terrainQueue.Enqueue(list3[n]); } } int num14 = 0; for (int num15 = 0; num15 < num12; num15++) { TileRequest tileRequest2 = list[num15]; if (!_terrainTiles.ContainsKey(tileRequest2.Key) && !_terrainQueuedKeys.Contains(tileRequest2.Key)) { _terrainQueue.Enqueue(tileRequest2); _terrainQueuedKeys.Add(tileRequest2.Key); num14++; } } _lastTerrainTileQueued = _terrainQueue.Count; int num16 = hashSet.Count - num14; _lastQueueBudgetStatus = "terrain requests " + list.Count + " capped to " + num12 + "/" + num4 + " (keep " + num16 + ", add " + num14 + ", remove " + num13 + ")"; } private void RunMovementRetentionSelfTestIfNeeded() { if (_movementRetentionSelfTestRun) { return; } _movementRetentionSelfTestRun = true; List list = new List(); for (int i = 0; i < 20; i++) { TileRequest tileRequest = new TileRequest(i, 0, i, i); tileRequest.IsResident = i < 10; list.Add(tileRequest); } list.Reverse(); list.Sort(TileRequest.CompareResidentThenDistance); bool flag = true; for (int j = 0; j < 10; j++) { if (!list[j].IsResident) { flag = false; } } bool flag2 = true; for (int k = 1; k < 10; k++) { if (list[k].Distance < list[k - 1].Distance) { flag2 = false; } } bool flag3 = true; for (int l = 11; l < 20; l++) { if (list[l].Distance < list[l - 1].Distance) { flag3 = false; } } int num = 12; int num2 = 0; int num3 = 0; for (int m = 0; m < num; m++) { if (list[m].IsResident) { num2++; } else { num3++; } } if (flag && flag2 && flag3 && num2 == 10 && num3 == 2) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[New Horizons Treelines] MOVEMENT RETENTION SELF-TEST PASSED -- resident-biased truncation kept all " + num2 + " already-resident synthetic tiles and added only " + num3 + " new ones under a tightened budget.")); } else { ((BaseUnityPlugin)this).Logger.LogError((object)("[New Horizons Treelines] MOVEMENT RETENTION SELF-TEST FAILED -- resident-biased desired-set truncation did not behave as expected (residentsFirst=" + flag + ", keptResident=" + num2 + "/10, keptNew=" + num3 + "/2).")); } } private void RunBlackForestCrossedPlaneSelfTestIfNeeded() { if (_blackForestCrossedPlaneSelfTestRun) { return; } _blackForestCrossedPlaneSelfTestRun = true; float num = 10f; float num2 = 0.37f; float num3 = num2 + MathF.PI / 2f; float num4 = float.MaxValue; bool flag = false; for (int i = 0; i < 36; i++) { float num5 = (float)i * (MathF.PI / 18f); float num6 = Mathf.Abs(Mathf.Sin(num5 - num2)) * num; float num7 = Mathf.Abs(Mathf.Sin(num5 - num3)) * num; float num8 = Mathf.Max(num6, num7); float num9 = num8 / num; if (num9 < num4) { num4 = num9; } if (num8 < num * 0.01f) { flag = true; } } if (!flag && num4 >= 0.65f) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[New Horizons Treelines] BLACK FOREST CROSSED-PLANE SELF-TEST PASSED -- projected visible width across " + 36 + " horizontal viewing angles never dropped below " + (num4 * 100f).ToString("F0", CultureInfo.InvariantCulture) + "% of card width.")); } else { ((BaseUnityPlugin)this).Logger.LogError((object)("[New Horizons Treelines] BLACK FOREST CROSSED-PLANE SELF-TEST FAILED -- worst-case projected width fraction " + num4.ToString("F3", CultureInfo.InvariantCulture) + " (collapsed to near-zero: " + flag + ").")); } } private void RunDeterministicRestoreSelfTestIfNeeded() { if (_deterministicSelfTestRun) { return; } if (_runExpensiveDeterministicStartupSelfTest == null || !_runExpensiveDeterministicStartupSelfTest.Value) { _deterministicSelfTestRun = true; _forestDeterministicRestoreDetail = "expensive four-tile startup stress test disabled; normal runtime tile-hash verification remains active"; if (!_expensiveStartupSelfTestSkipLogged) { _expensiveStartupSelfTestSkipLogged = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[New Horizons Treelines] EXPENSIVE DETERMINISTIC STARTUP SELF-TEST SKIPPED -- runtime deterministic restore checks remain active."); } } else if (_provider != null && _provider.IsReady && CanRenderCustomGeometry() && ForestAtlasMaterialsReady()) { _deterministicSelfTestRun = true; int num = Mathf.FloorToInt(_buildAnchor.x / ContinuityTileSize()); int num2 = Mathf.FloorToInt(_buildAnchor.z / ContinuityTileSize()); int num3 = num + 1; int num4 = num2; long num5 = TileKey(num, num2); long num6 = TileKey(num3, num4); ForestTile forestTile = BuildForestTile(num, num2); string text = ((forestTile != null) ? forestTile.ContentHash : "empty"); int num7 = ((forestTile != null) ? (forestTile.TreeCardCount + forestTile.CanopyCardCount) : 0); ForestTile forestTile2 = BuildForestTile(num3, num4); string text2 = ((forestTile2 != null) ? forestTile2.ContentHash : "empty"); int num8 = ((forestTile2 != null) ? (forestTile2.TreeCardCount + forestTile2.CanopyCardCount) : 0); forestTile?.Destroy(); forestTile2?.Destroy(); DeactivateGroundCardRecordsForTile(num5, deleteRecords: true); DeactivateGroundCardRecordsForTile(num6, deleteRecords: true); ForestTile forestTile3 = BuildForestTile(num3, num4); string text3 = ((forestTile3 != null) ? forestTile3.ContentHash : "empty"); int num9 = ((forestTile3 != null) ? (forestTile3.TreeCardCount + forestTile3.CanopyCardCount) : 0); ForestTile forestTile4 = BuildForestTile(num, num2); string text4 = ((forestTile4 != null) ? forestTile4.ContentHash : "empty"); int num10 = ((forestTile4 != null) ? (forestTile4.TreeCardCount + forestTile4.CanopyCardCount) : 0); forestTile4?.Destroy(); forestTile3?.Destroy(); DeactivateGroundCardRecordsForTile(num5, deleteRecords: true); DeactivateGroundCardRecordsForTile(num6, deleteRecords: true); _forestTileLastKnownHash.Remove(num5); _forestTileLastKnownHash.Remove(num6); _forestTileDeterminismRecords.Remove(num5); _forestTileDeterminismRecords.Remove(num6); if (text == text4 && num7 == num10 && text2 == text3 && num8 == num9) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[New Horizons Treelines] DETERMINISTIC TILE SELF-TEST PASSED -- tiles " + num + "," + num2 + " (" + num7 + " cards) and " + num3 + "," + num4 + " (" + num8 + " cards) produced identical content hashes across reversed build orders.")); return; } _forestDeterministicRestoreOk = false; _forestDeterministicRestoreDetail = "SELF-TEST FAILURE: order dependence between tiles " + num + "," + num2 + " and " + num3 + "," + num4; ((BaseUnityPlugin)this).Logger.LogError((object)("[New Horizons Treelines] DETERMINISTIC RESTORE VIOLATION -- release-blocking self-test failure: tile " + num + "," + num2 + " hash " + text + "/" + num7 + " (built first) vs " + text4 + "/" + num10 + " (built second); tile " + num3 + "," + num4 + " hash " + text2 + "/" + num8 + " vs " + text3 + "/" + num9 + ".")); } } private void ProcessBuildQueues() { _forestCurrentCpuBudgetMs = CurrentForestGenerationCpuBudgetMs(); _forestFrameBudgetStopwatch = Stopwatch.StartNew(); _forestMeshesUploadedThisFrame = 0; _forestMeshUploadTimeThisFrameMs = 0f; _forestCandidatesProcessedThisFrame = 0; _forestGroundingSamplesThisFrame = 0; _forestMeshVerticesThisFrame = 0; _forestTerrainSamplesThisFrame = 0; _forestFootprintChecksThisFrame = 0; _forestSlopeChecksThisFrame = 0; _forestMeshCardsAppendedThisFrame = 0; _forestChunkActivationsThisFrame = 0; _forestCompletedTileCommitsThisFrame = 0; RunDeterministicRestoreSelfTestIfNeeded(); RunMovementRetentionSelfTestIfNeeded(); RunBlackForestCrossedPlaneSelfTestIfNeeded(); if (AdaptiveHighPresetGovernorActive()) { int num = ((_adaptiveTerrainBuildIntervalFrames != null) ? Mathf.Max(2, _adaptiveTerrainBuildIntervalFrames.Value) : 4); bool flag = _terrainQueue.Count > 0 && (_forestAddQueue.Count == 0 || _adaptiveTerrainCadenceCounter >= num - 1); if (flag && !AdaptiveGenerationCoolingDown() && _adaptivePressure < 0.75f) { ProcessTerrainQueue(); _adaptiveTerrainCadenceCounter = 0; } else { ProcessForestStreaming(); _adaptiveTerrainCadenceCounter = Mathf.Min(num, _adaptiveTerrainCadenceCounter + 1); if (_terrainQueue.Count > 0 && (flag || AdaptiveGenerationCoolingDown() || _adaptivePressure >= 0.75f)) { _terrainBuildFramesDeferredForPerformance++; } } } else { ProcessTerrainQueue(); ProcessForestStreaming(); } ProcessForestRetirement(); if (!ForestGenerationFrameBudgetExpired()) { ProcessCoverageAuditQueue(); } if (!ForestGenerationFrameBudgetExpired() && CoverageRepairAllowedThisFrame()) { ProcessCoverageRepairQueue(); } else if (_coverageRepairQueue.Count > 0) { _startupCoverageRepairFramesDeferred++; } bool flag2 = _forestAddQueue.Count > 0; if (_rebuildTimingPending && !flag2 && _terrainQueue.Count == 0) { _lastRebuildDurationSeconds = Time.realtimeSinceStartup - _lastRebuildStartTime; _rebuildTimingPending = false; } if (_forestFrameBudgetStopwatch != null) { _forestFrameBudgetStopwatch.Stop(); _forestGenerationTimeThisFrameMs = (float)_forestFrameBudgetStopwatch.Elapsed.TotalMilliseconds; } } private TerrainTile BuildTerrainTile(int tileX, int tileZ) { EnsureRoot(); float num = FarTerrainTileSize(); float[] heightGrid; Mesh val = BuildTerrainMesh(tileX, tileZ, num, out heightGrid); if ((Object)(object)val == (Object)null) { return null; } bool flag = UsesFullResolutionProviderTerrainColour(); int resolution = ((_fallbackTerrainColourTextureResolution != null) ? Mathf.Clamp(_fallbackTerrainColourTextureResolution.Value, 32, 128) : 64); Texture2D val2 = (flag ? null : BuildTerrainTileTexture(tileX, tileZ, num, resolution)); TerrainTile terrainTile = new TerrainTile(tileX, tileZ, num, _root.transform); terrainTile.Filter.sharedMesh = val; terrainTile.Mesh = val; terrainTile.HeightGrid = heightGrid; terrainTile.GridResolution = FarTerrainMeshResolution(); if (flag) { ((Renderer)terrainTile.Renderer).sharedMaterial = _sharedTerrainMaterial; _fullResolutionTerrainTilesBuilt++; } else if ((Object)(object)val2 != (Object)null) { terrainTile.Texture = val2; terrainTile.Material = CreateTextureMaterial(val2, "Donegal Horizon Terrain Material " + tileX + "," + tileZ); ((Renderer)terrainTile.Renderer).sharedMaterial = terrainTile.Material; } else { if (!_provider.UsesSharedTerrainTexture) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Provider did not expose a shared Donegal terrain texture. Terrain tile skipped; no per-tile fallback material will be created."); terrainTile.Destroy(); return null; } ((Renderer)terrainTile.Renderer).sharedMaterial = _sharedTerrainMaterial; } ConfigureRenderer(terrainTile.Renderer); return terrainTile; } private void AppendForestChunkFromMeshSet(ForestTile tile, ForestChunkMeshSet meshSet) { ForestChunk forestChunk = new ForestChunk(meshSet.ChunkX, meshSet.ChunkZ, meshSet.ChunkSize, tile.Root.transform, meshSet.Shard); forestChunk.LogicalTreeCardCount = meshSet.LogicalTreeCardCount; forestChunk.CrossedLogicalTreeCardCount = meshSet.CrossedLogicalTreeCardCount; forestChunk.SinglePlaneLogicalTreeCardCount = meshSet.SinglePlaneLogicalTreeCardCount; if ((Object)(object)meshSet.MassMesh != (Object)null) { forestChunk.MassFilter.sharedMesh = meshSet.MassMesh; forestChunk.MassMesh = meshSet.MassMesh; ((Renderer)forestChunk.MassRenderer).sharedMaterial = _forestMaterial; ConfigureRenderer(forestChunk.MassRenderer); } if ((Object)(object)meshSet.TreeCardMesh != (Object)null && (Object)(object)_treeCardMaterial != (Object)null) { forestChunk.TreeFilter.sharedMesh = meshSet.TreeCardMesh; forestChunk.TreeCardMesh = meshSet.TreeCardMesh; ((Renderer)forestChunk.TreeRenderer).sharedMaterial = _treeCardMaterial; ConfigureTreeCardRenderer(forestChunk.TreeRenderer); } if ((Object)(object)meshSet.CanopyMesh != (Object)null && (Object)(object)_canopyCardMaterial != (Object)null) { forestChunk.CanopyFilter.sharedMesh = meshSet.CanopyMesh; forestChunk.CanopyMesh = meshSet.CanopyMesh; ((Renderer)forestChunk.CanopyRenderer).sharedMaterial = _canopyCardMaterial; ConfigureTreeCardRenderer(forestChunk.CanopyRenderer); } if ((Object)(object)meshSet.MountainBiomeMesh != (Object)null && (Object)(object)_mountainBiomeCardMaterial != (Object)null) { forestChunk.MountainBiomeFilter.sharedMesh = meshSet.MountainBiomeMesh; forestChunk.MountainBiomeMesh = meshSet.MountainBiomeMesh; ((Renderer)forestChunk.MountainBiomeRenderer).sharedMaterial = _mountainBiomeCardMaterial; ConfigureTreeCardRenderer(forestChunk.MountainBiomeRenderer); } if ((Object)(object)meshSet.SwampBiomeMesh != (Object)null && (Object)(object)_swampBiomeCardMaterial != (Object)null) { forestChunk.SwampBiomeFilter.sharedMesh = meshSet.SwampBiomeMesh; forestChunk.SwampBiomeMesh = meshSet.SwampBiomeMesh; ((Renderer)forestChunk.SwampBiomeRenderer).sharedMaterial = _swampBiomeCardMaterial; ConfigureTreeCardRenderer(forestChunk.SwampBiomeRenderer); _swampChunksBuilt++; _swampRenderersCreated++; } forestChunk.RecalculateBounds(); forestChunk.SetEnabled(enabled: false); tile.Chunks.Add(forestChunk); } private ForestChunkBuffers RentForestChunkBuffers(int chunkX, int chunkZ, float chunkSize, int shard, ForestBuildContinuation continuation) { ForestChunkBuffers forestChunkBuffers; if (_forestChunkBufferPool.Count > 0) { forestChunkBuffers = _forestChunkBufferPool.Pop(); forestChunkBuffers.Prepare(chunkX, chunkZ, chunkSize, shard); } else { forestChunkBuffers = new ForestChunkBuffers(chunkX, chunkZ, chunkSize, shard); _forestPooledBufferAllocations++; } continuation?.LeasedChunkBuffers.Add(forestChunkBuffers); return forestChunkBuffers; } private void ReturnForestChunkBuffers(ForestChunkBuffers buffers) { if (buffers != null && !buffers.Pooled) { buffers.ClearForPool(); if (_forestChunkBufferPool.Count < 64) { _forestChunkBufferPool.Push(buffers); } } } private CoverageRepairMeshBuffer RentCoverageRepairMeshBuffer() { if (_coverageRepairMeshBufferPool.Count > 0) { return _coverageRepairMeshBufferPool.Pop(); } _coveragePooledBufferAllocations++; return new CoverageRepairMeshBuffer(); } private void ReturnCoverageRepairMeshBuffer(CoverageRepairMeshBuffer buffer) { if (buffer != null) { buffer.Vertices.Clear(); buffer.Uvs.Clear(); buffer.Triangles.Clear(); buffer.Tile = null; buffer.Chunk = null; buffer.Mesh = null; if (_coverageRepairMeshBufferPool.Count < 32) { _coverageRepairMeshBufferPool.Push(buffer); } } } private Texture2D BuildTerrainTileTexture(int tileX, int tileZ, float tileSize, int resolution) { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //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) if (_provider == null) { return null; } int num = Mathf.Clamp(resolution, 16, 128); Color32[] array = (Color32[])(object)new Color32[num * num]; float num2 = (float)tileX * tileSize; float num3 = (float)tileZ * tileSize; for (int i = 0; i < num; i++) { float num4 = ((num > 1) ? ((float)i / (float)(num - 1)) : 0f); float num5 = Mathf.Lerp(num3, num3 + tileSize, num4); for (int j = 0; j < num; j++) { float num6 = ((num > 1) ? ((float)j / (float)(num - 1)) : 0f); float num7 = Mathf.Lerp(num2, num2 + tileSize, num6); float distance = FlatDistance(num7, num5, _buildAnchor.x, _buildAnchor.z); array[i * num + j] = ComputeTerrainDisplayColor(num7, num5, distance); } } Texture2D val = new Texture2D(num, num, (TextureFormat)3, true, false); ((Object)val).name = "DonegalHorizonTerrainTileTexture_" + tileX + "_" + tileZ; ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)1; val.SetPixels32(array); val.Apply(true, false); return val; } private ForestTile BuildForestTile(int tileX, int tileZ) { EnsureRoot(); float num = ContinuityTileSize(); float ax = ((float)tileX + 0.5f) * num; float az = ((float)tileZ + 0.5f) * num; ForestRing ring = RingForDistance(FlatDistance(ax, az, _buildAnchor.x, _buildAnchor.z)); bool optionalCoverageWasEnabled = _buildingReinforcementJob || RingPrimaryCoverageComplete(ring); long num2 = TileKey(tileX, tileZ); DeactivateGroundCardRecordsForTile(num2, deleteRecords: true); _currentGroundCardOwnerTileKey = num2; bool flag = false; ForestBuildResult result; try { ForestBuildContinuation forestBuildContinuation = new ForestBuildContinuation { GroundOwnerKey = num2, OptionalCoverageWasEnabled = optionalCoverageWasEnabled, GeometryOverloadState = _viewFacingForestOverloadState }; forestBuildContinuation.Enumerator = BuildForestContinuityMeshesResumable(tileX, tileZ, forestBuildContinuation); while (forestBuildContinuation.Enumerator.MoveNext()) { } result = forestBuildContinuation.Result; flag = true; } finally { _currentGroundCardOwnerTileKey = long.MinValue; if (!flag) { DeactivateGroundCardRecordsForTile(num2, deleteRecords: true); } } return CreateForestTileFromResult(tileX, tileZ, result, optionalCoverageWasEnabled); } private ForestTile CreateForestTileFromResult(int tileX, int tileZ, ForestBuildResult result, bool optionalCoverageWasEnabled) { ForestTileAssemblyResult forestTileAssemblyResult = new ForestTileAssemblyResult(); IEnumerator enumerator = CreateForestTileFromResultResumable(tileX, tileZ, result, optionalCoverageWasEnabled, forestTileAssemblyResult); while (enumerator.MoveNext()) { } enumerator.Dispose(); return forestTileAssemblyResult.Tile; } private IEnumerator CreateForestTileFromResultResumable(int tileX, int tileZ, ForestBuildResult result, bool optionalCoverageWasEnabled, ForestTileAssemblyResult assembly) { long tileKey = TileKey(tileX, tileZ); if (result == null || result.Chunks == null || result.Chunks.Count == 0) { DeactivateGroundCardRecordsForTile(tileKey, deleteRecords: true); assembly.Tile = null; yield break; } ForestTile tile = (assembly.Tile = new ForestTile(tileX, tileZ, ContinuityTileSize(), _root.transform)); tile.ClusterCount = result.ClusterCount; tile.TreeCardCount = result.TreeCardCount; tile.CanopyCardCount = result.CanopyCardCount; tile.NearestDensity = result.NearestDensity; tile.PrimaryPassOnly = !optionalCoverageWasEnabled; tile.CandidateTotal = result.CandidateTotal; tile.CandidatesCompleted = result.CandidatesCompleted; tile.StableCardRecords = result.StableCardRecords; tile.GeometryOverloadState = result.GeometryOverloadState; for (int i = 0; i < result.Chunks.Count; i++) { AppendForestChunkFromMeshSet(tile, result.Chunks[i]); yield return i + 1; } _lastBuiltForestClusters += result.ClusterCount; _lastBuiltTreeCards += result.TreeCardCount; _lastBuiltCanopyCards += result.CanopyCardCount; float num = DistanceToTile(_buildAnchor.x, _buildAnchor.z, tileX, tileZ, ContinuityTileSize()); tile.GenerationSignatureBase = CurrentForestGenerationSignatureBase(); tile.WasBoundaryBandTile = num <= NativeTreelineHandoff() + 128f + ContinuityTileSize(); tile.BuiltHBucket = NativeTreelineHandoff(); tile.BuiltOBucket = NativeTreelineSeamOverlap(); tile.EstimatedVertexCount = EstimateForestTileVertexCount(tile); tile.ContentHash = ComputeForestTileContentHash(tile); long num2 = TileKey(tileX, tileZ); string text = tile.GenerationSignatureBase + "|pass=" + (tile.PrimaryPassOnly ? "primary" : "full") + "|ring=" + RingForDistance(num).ToString() + "|viewGeometry=" + tile.GeometryOverloadState.ToString() + "|anchor=" + Mathf.RoundToInt(_buildAnchor.x) + "," + Mathf.RoundToInt(_buildAnchor.z) + "|budget=" + _remainingTreeCardPlaneBudget + "," + _remainingCanopyPlaneBudget; bool flag = tile.CandidateTotal > 0 && tile.CandidatesCompleted == tile.CandidateTotal; if (_forestTileDeterminismRecords.TryGetValue(num2, out var value)) { bool flag2 = value.CandidateTotal > 0 && value.CandidatesCompleted == value.CandidateTotal; if (!flag || !flag2) { _determinismComparisonsSkippedPartial++; } else if (!string.Equals(value.GenerationSignature, text, StringComparison.Ordinal)) { _determinismComparisonsSkippedSignature++; } else if (!string.Equals(value.Hash, tile.ContentHash, StringComparison.Ordinal)) { _forestDeterministicRestoreOk = false; string text2 = FirstDifferingStableCardRecord(value.StableCardRecords, tile.StableCardRecords); _forestDeterministicRestoreDetail = "MISMATCH at tile " + tileX + "," + tileZ + " (hash " + value.Hash + " -> " + tile.ContentHash + ", " + text2 + ")"; if (_determinismWarningsThisEpoch.Add(num2)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[New Horizons Treelines] DETERMINISTIC RESTORE VIOLATION at tile " + tileX + "," + tileZ + ": content hash changed from " + value.Hash + " to " + tile.ContentHash + "; " + text2 + ".")); } else { _determinismWarningsSuppressed++; } } else { _forestDeterministicRestoreOk = true; _forestDeterministicRestoreDetail = "OK (last verified full tile " + tileX + "," + tileZ + ")"; } } _forestTileLastKnownHash[num2] = tile.ContentHash; _forestTileDeterminismRecords[num2] = new ForestDeterminismRecord { Hash = tile.ContentHash, GenerationSignature = text, CandidateTotal = tile.CandidateTotal, CandidatesCompleted = tile.CandidatesCompleted, StableCardRecords = (tile.StableCardRecords ?? new int[0]) }; bool flag3 = false; bool flag4 = true; Vector3 val = (((Object)(object)_root != (Object)null) ? _root.transform.position : Vector3.zero); for (int j = 0; j < tile.Chunks.Count; j++) { ForestChunk forestChunk = tile.Chunks[j]; bool flag5 = (Object)(object)forestChunk.MassMesh != (Object)null || (Object)(object)forestChunk.TreeCardMesh != (Object)null || (Object)(object)forestChunk.CanopyMesh != (Object)null || (Object)(object)forestChunk.MountainBiomeMesh != (Object)null || (Object)(object)forestChunk.SwampBiomeMesh != (Object)null; if ((Object)(object)forestChunk.SwampBiomeMesh != (Object)null) { flag3 = true; } if (!flag5) { continue; } Vector3 val2 = val + forestChunk.LocalOrigin; float num3 = Vector3.Distance(forestChunk.Root.transform.position, val2); if (num3 > _swampMaxCoordinateErrorMeters) { _swampMaxCoordinateErrorMeters = num3; } if (num3 > _maxFinalWorldHeightmapError) { _maxFinalWorldHeightmapError = num3; } if (num3 > 0.01f) { flag4 = false; _groundTransformOk = false; _groundTransformDetail = "VIOLATION at " + ((Object)forestChunk.Root).name + ": position error " + num3.ToString("F3", CultureInfo.InvariantCulture) + "m"; if ((Object)(object)forestChunk.SwampBiomeMesh != (Object)null) { _swampMeshCoordinateViolations++; } _lastSwampFloatingChunkKey = ((Object)forestChunk.Root).name; _lastStackedCardViolation = _groundTransformDetail; if (Time.realtimeSinceStartup - _lastGroundTransformWarningRealtime >= 5f) { _lastGroundTransformWarningRealtime = Time.realtimeSinceStartup; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[New Horizons Treelines] GROUND TRANSFORM VIOLATION at " + ((Object)forestChunk.Root).name + ": position error " + num3.ToString("F3", CultureInfo.InvariantCulture) + "m.")); } } } if (flag4 && _groundTransformOk) { _groundTransformDetail = "OK (chunk-local vertices reconstructed and height-checked; last tile " + tileX + "," + tileZ + ")"; } if (flag3) { _swampChunksFreshlyBuilt++; } assembly.Tile = tile; } private IEnumerator BuildForestTileJobResumable(ForestAddJob job, ForestRing jobRing) { EnsureRoot(); float num = ContinuityTileSize(); float ax = ((float)job.X + 0.5f) * num; float az = ((float)job.Z + 0.5f) * num; bool optionalCoverageWasEnabled = !_currentBudgetStarvationDetected && (_buildingReinforcementJob || RingPrimaryCoverageComplete(RingForDistance(FlatDistance(ax, az, _buildAnchor.x, _buildAnchor.z)))); ForestBuildContinuation continuation = new ForestBuildContinuation { Job = job, Ring = jobRing, OptionalCoverageWasEnabled = optionalCoverageWasEnabled, GroundOwnerKey = TileKey(job.X, job.Z), StartedRealtime = Time.realtimeSinceStartup, GeometryOverloadState = _viewFacingForestOverloadState }; DeactivateGroundCardRecordsForTile(continuation.GroundOwnerKey, deleteRecords: true); continuation.Enumerator = BuildForestContinuityMeshesResumable(job.X, job.Z, continuation); _activeForestBuild = continuation; _forestPartiallyProcessedResumableTiles = 1; while (true) { if (job.Epoch != _forestGenerationEpoch) { _forestCancelledObsoleteJobs++; DeactivateGroundCardRecordsForTile(continuation.GroundOwnerKey, deleteRecords: true); FinishActiveForestBuildState(); yield break; } bool flag = false; Exception ex = null; Stopwatch stopwatch = Stopwatch.StartNew(); _currentGroundCardOwnerTileKey = continuation.GroundOwnerKey; try { flag = continuation.Enumerator.MoveNext(); } catch (Exception ex2) { ex = ex2; } finally { _currentGroundCardOwnerTileKey = long.MinValue; stopwatch.Stop(); } float num2 = (float)stopwatch.Elapsed.TotalMilliseconds; _forestGenerationTimeThisFrameMs += num2; if (num2 > _forestLongestCandidateBatchMs) { _forestLongestCandidateBatchMs = num2; } if (num2 > _forestLongestResumableStepMs) { _forestLongestResumableStepMs = num2; } if (ex != null) { HandleFailedResumableForestJob(job, continuation, ex); yield break; } if (!flag) { break; } _forestCurrentJobStage = "candidate generation " + job.X + "," + job.Z + " " + continuation.CandidateIndex + "/" + continuation.CandidateTotal; yield return null; } _forestCurrentJobStage = "mesh activation " + job.X + "," + job.Z; ForestTileAssemblyResult assembly = new ForestTileAssemblyResult(); IEnumerator assemblyEnumerator = CreateForestTileFromResultResumable(job.X, job.Z, continuation.Result, continuation.OptionalCoverageWasEnabled, assembly); while (true) { if (job.Epoch != _forestGenerationEpoch) { assemblyEnumerator.Dispose(); if (assembly.Tile != null) { assembly.Tile.Destroy(); } _forestCancelledGenerationJobs++; DeactivateGroundCardRecordsForTile(continuation.GroundOwnerKey, deleteRecords: true); FinishActiveForestBuildState(); yield break; } bool flag2 = false; Exception ex3 = null; Stopwatch stopwatch2 = Stopwatch.StartNew(); try { flag2 = assemblyEnumerator.MoveNext(); } catch (Exception ex4) { ex3 = ex4; } stopwatch2.Stop(); float num3 = (float)stopwatch2.Elapsed.TotalMilliseconds; _forestGenerationTimeThisFrameMs += num3; if (num3 > _forestLongestMeshBatchMs) { _forestLongestMeshBatchMs = num3; } if (num3 > _forestLongestResumableStepMs) { _forestLongestResumableStepMs = num3; } if (ex3 != null) { assemblyEnumerator.Dispose(); if (assembly.Tile != null) { assembly.Tile.Destroy(); } HandleFailedResumableForestJob(job, continuation, ex3); yield break; } if (!flag2) { break; } _forestChunkActivationsThisFrame++; yield return null; } assemblyEnumerator.Dispose(); ForestTile tile = assembly.Tile; if (continuation.CandidateIndex >= continuation.CandidateTotal) { _forestTilesCompletedFullCandidateSet++; _forestCompletedCandidateEvaluations += continuation.CandidateIndex; } else { _cardsBlockedByCandidateCompletion += continuation.CandidateTotal - continuation.CandidateIndex; } if (tile != null) { _forestCurrentJobStage = "mesh upload " + job.X + "," + job.Z; _forestTiles[job.Key] = tile; ActivatePrimaryCoverageRecordsForTile(job.Key); _activeTreePlanesReported += tile.TreeCardCount; _activeCanopyPlanesReported += tile.CanopyCardCount; _forestPlanesAddedThisUpdate += tile.TreeCardCount + tile.CanopyCardCount; _forestChunksBuiltThisFrame++; _forestCompletedTileCommitsThisFrame++; _forestMeshVerticesThisFrame += EstimateForestTileVertexCount(tile); _forestCompletedTilesTotal++; _lastPrimaryProgressRealtime = Time.realtimeSinceStartup; float num4 = Mathf.Max(0f, Time.realtimeSinceStartup - continuation.StartedRealtime) * 1000f; _forestChunkBuildMsSum += num4; _forestChunkBuildSampleCount++; if (num4 > _forestLongestChunkBuildMs) { _forestLongestChunkBuildMs = num4; } _ringPlaneCountsCache = ComputeRingPlaneCounts(); ScanTileForCoverageHoles(tile, jobRing); } FinishActiveForestBuildState(); UpdateRingSectorCoverageState(); } private void HandleFailedResumableForestJob(ForestAddJob job, ForestBuildContinuation continuation, Exception exception) { DeactivateGroundCardRecordsForTile(continuation.GroundOwnerKey, deleteRecords: true); job.RetryCount++; _forestJobsRestartedUnexpectedly++; int num = ((_maxForestJobRetries != null) ? _maxForestJobRetries.Value : 2); if (Time.realtimeSinceStartup - _lastForestJobWarningRealtime >= 5f) { _lastForestJobWarningRealtime = Time.realtimeSinceStartup; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[New Horizons Treelines] Resumable forest tile build failed (key " + job.Key + ", candidate " + continuation.CandidateIndex + "/" + continuation.CandidateTotal + ", attempt " + job.RetryCount + "): " + exception.GetType().Name + ": " + exception.Message)); } if (job.RetryCount <= num && job.Epoch == _forestGenerationEpoch) { _forestAddQueue.Add(job); _forestAddJobsByKey[job.Key] = job; } else { _forestFailedJobsPermanent++; _cardsBlockedByCandidateCompletion += Mathf.Max(0, continuation.CandidateTotal - continuation.CandidateIndex); } FinishActiveForestBuildState(); } private void FinishActiveForestBuildState() { if (_activeForestBuild != null) { if (_activeForestBuild.Enumerator != null) { _activeForestBuild.Enumerator.Dispose(); } for (int i = 0; i < _activeForestBuild.LeasedChunkBuffers.Count; i++) { ReturnForestChunkBuffers(_activeForestBuild.LeasedChunkBuffers[i]); } _activeForestBuild.LeasedChunkBuffers.Clear(); } _activeForestBuild = null; _buildingPrimaryCoverageJob = false; _buildingReinforcementJob = false; _forestActiveResumableJobs = 0; _forestPartiallyProcessedResumableTiles = 0; _forestCurrentJobStage = "idle"; _forestCurrentlyBuildingTileKey = long.MinValue; _currentGroundCardOwnerTileKey = long.MinValue; } private static int EstimateForestTileVertexCount(ForestTile tile) { int num = 0; for (int i = 0; i < tile.Chunks.Count; i++) { ForestChunk forestChunk = tile.Chunks[i]; if ((Object)(object)forestChunk.MassMesh != (Object)null) { num += forestChunk.MassMesh.vertexCount; } if ((Object)(object)forestChunk.TreeCardMesh != (Object)null) { num += forestChunk.TreeCardMesh.vertexCount; } if ((Object)(object)forestChunk.CanopyMesh != (Object)null) { num += forestChunk.CanopyMesh.vertexCount; } if ((Object)(object)forestChunk.MountainBiomeMesh != (Object)null) { num += forestChunk.MountainBiomeMesh.vertexCount; } if ((Object)(object)forestChunk.SwampBiomeMesh != (Object)null) { num += forestChunk.SwampBiomeMesh.vertexCount; } } return num; } private static string ComputeForestTileContentHash(ForestTile tile) { int hash = 17; for (int i = 0; i < tile.Chunks.Count; i++) { ForestChunk forestChunk = tile.Chunks[i]; hash = HashMeshForDeterminism(hash, forestChunk.MassMesh); hash = HashMeshForDeterminism(hash, forestChunk.TreeCardMesh); hash = HashMeshForDeterminism(hash, forestChunk.CanopyMesh); hash = HashMeshForDeterminism(hash, forestChunk.MountainBiomeMesh); hash = HashMeshForDeterminism(hash, forestChunk.SwampBiomeMesh); } return hash.ToString("X8", CultureInfo.InvariantCulture); } private static string FirstDifferingStableCardRecord(int[] previous, int[] current) { previous = previous ?? new int[0]; current = current ?? new int[0]; int num = Mathf.Min(previous.Length, current.Length); for (int i = 0; i < num; i++) { if (previous[i] != current[i]) { return "first differing stable card record " + i + " (" + previous[i].ToString("X8", CultureInfo.InvariantCulture) + " -> " + current[i].ToString("X8", CultureInfo.InvariantCulture) + ")"; } } if (previous.Length != current.Length) { return "first differing stable card record " + num + " (record count " + previous.Length + " -> " + current.Length + ")"; } return "stable card records match; difference is mesh-only"; } private static int HashMeshForDeterminism(int hash, Mesh mesh) { if ((Object)(object)mesh == (Object)null) { return hash * 31; } hash = hash * 31 + mesh.vertexCount; Vector3[] vertices = mesh.vertices; if (vertices.Length != 0) { hash = hash * 31 + ((object)Unsafe.As(ref vertices[0])/*cast due to .constrained prefix*/).GetHashCode(); } if (vertices.Length > 2) { hash = hash * 31 + ((object)Unsafe.As(ref vertices[vertices.Length / 2])/*cast due to .constrained prefix*/).GetHashCode(); } if (vertices.Length > 1) { hash = hash * 31 + ((object)Unsafe.As(ref vertices[^1])/*cast due to .constrained prefix*/).GetHashCode(); } return hash; } private Mesh BuildTerrainMesh(int tileX, int tileZ, float tileSize, out float[] heightGrid) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Expected O, but got Unknown //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) heightGrid = null; int num = FarTerrainMeshResolution(); int num2 = num + 1; Vector3[] array = (Vector3[])(object)new Vector3[num2 * num2]; Vector2[] array2 = (Vector2[])(object)new Vector2[num2 * num2]; List list = new List(num * num * 12); float num3 = (float)tileX * tileSize; float num4 = (float)tileZ * tileSize; bool flag = UsesFullResolutionProviderTerrainColour(); int num5 = 0; for (int i = 0; i <= num; i++) { float num6 = Mathf.Lerp(num4, num4 + tileSize, (float)i / (float)num); for (int j = 0; j <= num; j++) { float num7 = Mathf.Lerp(num3, num3 + tileSize, (float)j / (float)num); WorldSurfaceSample sample; float num8 = (_provider.TrySample(num7, num6, out sample) ? sample.GroundY : 0f); array[num5] = new Vector3(num7, num8 + _verticalOffset.Value, num6); array2[num5] = (Vector2)((flag && _provider != null) ? _provider.GetTerrainUv(num7, num6) : new Vector2((float)j / (float)num, (float)i / (float)num)); num5++; } } for (int k = 0; k < num; k++) { for (int l = 0; l < num; l++) { float x = num3 + ((float)l + 0.5f) * tileSize / (float)num; float z = num4 + ((float)k + 0.5f) * tileSize / (float)num; if (InsideWorld(x, z)) { int num9 = k * num2 + l; int num10 = num9 + 1; int num11 = num9 + num2; int num12 = num11 + 1; if (OutsideExclusion(array[num9], 0f) && OutsideExclusion(array[num10], 0f) && OutsideExclusion(array[num11], 0f) && OutsideExclusion(array[num12], 0f)) { AddTriangleDoubleSided(list, num9, num11, num10); AddTriangleDoubleSided(list, num10, num11, num12); } } } } if (list.Count == 0) { return null; } heightGrid = new float[array.Length]; for (int m = 0; m < array.Length; m++) { heightGrid[m] = array[m].y; } Mesh val = new Mesh(); ((Object)val).name = "DonegalHorizonTerrain_" + tileX + "_" + tileZ; if (array.Length > 65000) { val.indexFormat = (IndexFormat)1; } val.vertices = array; val.uv = array2; val.SetTriangles(list, 0, true); val.RecalculateNormals(); val.RecalculateBounds(); return val; } private static int PrimaryTreePlaneTargetForRing(ForestRing ring) { return ring switch { ForestRing.Handoff => 960, ForestRing.Near => 720, ForestRing.Mid => 360, ForestRing.Far => 192, _ => 96, }; } private static float GroundSupportWidth(float visualWidth, Biome biome, ForestPlacementKind kind) { //IL_005f: 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) float num = Mathf.Max(0.5f, visualWidth); switch (kind) { case ForestPlacementKind.ProxyMass: return num; case ForestPlacementKind.CanopyCard: { float num5 = (IsSwampBiome(biome) ? 4f : 5f); float num6 = Mathf.Max(0.5f, Mathf.Min(num, num5)); float num7 = Mathf.Min(2f, num6); return Mathf.Clamp(num * 0.3f, num7, num6); } default: { float num2 = (IsSwampBiome(biome) ? 3f : 3.5f); float num3 = Mathf.Max(0.5f, Mathf.Min(num, num2)); float num4 = Mathf.Min(1.5f, num3); return Mathf.Clamp(num * 0.2f, num4, num3); } } } private bool AllowsDetailedTreeCoastalOverhang(Biome biome, ForestPlacementKind kind) { //IL_0017: 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_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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 if (_allowDetailedTreeFoliageOverhangAtCoast == null || !_allowDetailedTreeFoliageOverhangAtCoast.Value) { return false; } if (IsSwampBiome(biome)) { return false; } if (kind != ForestPlacementKind.TreeCard && kind != ForestPlacementKind.BiomeCard) { return false; } if ((biome & 8) == 0) { return (biome & 1) > 0; } return true; } private float DetailedTreeCoastalSafetyWidth(float visualWidth, Biome biome, ForestPlacementKind kind) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (!AllowsDetailedTreeCoastalOverhang(biome, kind)) { return Mathf.Max(0.5f, visualWidth); } float num = ((_coastalDetailedTreeWaterSafetyWidth != null) ? _coastalDetailedTreeWaterSafetyWidth.Value : 3.5f); return Mathf.Min(Mathf.Max(1f, visualWidth), Mathf.Clamp(num, 1f, 8f)); } private float DetailedTreeCoastalNearWaterRadius(Biome biome, ForestPlacementKind kind) { //IL_0001: 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) if (!AllowsDetailedTreeCoastalOverhang(biome, kind)) { if (!IsSwampBiome(biome)) { return _nonSwampNearWaterRejectRadius.Value; } return _swampNearWaterRejectRadius.Value; } if (_coastalDetailedTreeNearWaterRejectRadius == null) { return 2.5f; } return Mathf.Max(0f, _coastalDetailedTreeNearWaterRejectRadius.Value); } private float DetailedTreeCoastalMinimumAboveWater(Biome biome, ForestPlacementKind kind) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (!AllowsDetailedTreeCoastalOverhang(biome, kind)) { return MinimumLandAboveWater(biome); } if (_coastalDetailedTreeMinimumAboveWater == null) { return 0.2f; } return Mathf.Max(0.05f, _coastalDetailedTreeMinimumAboveWater.Value); } private IEnumerator BuildForestContinuityMeshesResumable(int tileX, int tileZ, ForestBuildContinuation continuation) { _currentForestBuildGeometryState = continuation.GeometryOverloadState; _currentTilePostMeshViolationCount = 0; _currentTilePostMeshWorstError = 0f; _currentTilePostMeshWorstDetail = "none"; MaybeRollHandoffTraceWindow(); int clusterCount = 0; int treeCardCount = 0; int canopyCardCount = 0; List stableCardRecords = new List(256); float nearestDensity = 0f; float num = ContinuityTileSize(); float cell = ClusterCellSize(); float candidateSpacing = HandoffFillCandidateSpacing(); int maxClusters = MaximumClustersPerTile(); int treePlaneBudget = Mathf.Min(MaxTreeCardPlanesPerTile(), Mathf.Max(0, _remainingTreeCardPlaneBudget)); int canopyPlaneBudget = Mathf.Min(MaxCanopyPlanesPerTile(), Mathf.Max(0, _remainingCanopyPlaneBudget)); int cells = Mathf.CeilToInt(num / candidateSpacing); float startX = (float)tileX * num; float startZ = (float)tileZ * num; int tileSeed = Hash(tileX, tileZ, _provider.StableSeed ^ 0x914F); Dictionary<(int size, int x, int z, int shard), ForestChunkBuffers> chunkBuffers = new Dictionary<(int, int, int, int), ForestChunkBuffers>(); float boundaryChunkSize = BoundaryTreelineChunkSize(); float boundaryBandOuter = NativeTreelineHandoff() + Mathf.Max(128f, HandoffFillBandWidth()); float handoffFillInner = ContinuityStart(); float handoffFillOuter = handoffFillInner + HandoffFillBandWidth(); float ax = startX + num * 0.5f; float az = startZ + num * 0.5f; ForestRing ring = RingForDistance(FlatDistance(ax, az, _buildAnchor.x, _buildAnchor.z)); bool allowOptionalCoverage = _buildingReinforcementJob || RingPrimaryCoverageComplete(ring); int primaryTreePlaneTargetForThisTile = (_buildingPrimaryCoverageJob ? Mathf.Min(treePlaneBudget, PrimaryTreePlaneTargetForRing(ring)) : treePlaneBudget); int num2 = EffectiveMaximumCandidateCellsPerTileBuild(); int totalCandidateCells = Mathf.Max(1, cells * cells); int targetCandidateCells = Mathf.Min(totalCandidateCells, num2); int candidatesPerStep = CandidateEvaluationsPerResumableStep(); int candidatesEvaluatedThisTile = 0; int candidatesEvaluatedThisStep = 0; int cardsAtStepStart = 0; int forestTerrainSamplesThisFrame = _forestTerrainSamplesThisFrame; int forestFootprintChecksThisFrame = _forestFootprintChecksThisFrame; int forestSlopeChecksThisFrame = _forestSlopeChecksThisFrame; Stopwatch candidateSliceWatch = Stopwatch.StartNew(); continuation.CandidateTotal = targetCandidateCells; Vector2 val = default(Vector2); for (int z = 0; z < cells; z++) { _handoffFillLastRowAcceptedX = float.NaN; _handoffFillLastRowZ = float.NaN; for (int x = 0; x < cells; x++) { int num3 = z * cells + x; if (targetCandidateCells < totalCandidateCells) { long num4 = (long)num3 * (long)targetCandidateCells / totalCandidateCells; long num5 = (long)(num3 + 1) * (long)targetCandidateCells / totalCandidateCells; if (num5 == num4) { continue; } } int num6 = ((_cardsAppendedToMeshPerResumableStep != null) ? Mathf.Clamp(_cardsAppendedToMeshPerResumableStep.Value, 8, 256) : 48); int num7 = (_forestGenerationPressureMode ? Mathf.Min(16, num6) : num6); int num8 = ((_terrainGroundSamplesPerResumableStep != null) ? Mathf.Clamp(_terrainGroundSamplesPerResumableStep.Value, 4, 128) : 24); int num9 = ((_footprintValidationsPerResumableStep != null) ? Mathf.Clamp(_footprintValidationsPerResumableStep.Value, 2, 64) : 12); int num10 = ((_slopeValidationsPerResumableStep != null) ? Mathf.Clamp(_slopeValidationsPerResumableStep.Value, 2, 64) : 16); bool flag = treeCardCount + canopyCardCount - cardsAtStepStart >= num7; bool flag2 = _forestTerrainSamplesThisFrame - forestTerrainSamplesThisFrame >= num8; bool flag3 = _forestFootprintChecksThisFrame - forestFootprintChecksThisFrame >= num9; bool flag4 = _forestSlopeChecksThisFrame - forestSlopeChecksThisFrame >= num10; bool flag5 = candidateSliceWatch.Elapsed.TotalMilliseconds >= (double)_forestCurrentCpuBudgetMs; if (candidatesEvaluatedThisStep >= candidatesPerStep || flag || flag2 || flag3 || flag4 || flag5) { continuation.CandidateIndex = candidatesEvaluatedThisTile; _forestCurrentJobCandidateIndex = candidatesEvaluatedThisTile; _forestCurrentJobCandidateTotal = targetCandidateCells; _forestCandidatesProcessedThisFrame += candidatesEvaluatedThisStep; _forestGroundingSamplesThisFrame += candidatesEvaluatedThisStep; _forestMeshCardsAppendedThisFrame += Mathf.Max(0, treeCardCount + canopyCardCount - cardsAtStepStart); candidatesEvaluatedThisStep = 0; cardsAtStepStart = treeCardCount + canopyCardCount; if (flag2 || flag3 || flag4) { _forestLongestGroundingSliceMs = Mathf.Max(_forestLongestGroundingSliceMs, (float)candidateSliceWatch.Elapsed.TotalMilliseconds); } candidateSliceWatch.Reset(); yield return candidatesEvaluatedThisTile; candidateSliceWatch.Start(); forestTerrainSamplesThisFrame = _forestTerrainSamplesThisFrame; forestFootprintChecksThisFrame = _forestFootprintChecksThisFrame; forestSlopeChecksThisFrame = _forestSlopeChecksThisFrame; } candidatesEvaluatedThisTile++; candidatesEvaluatedThisStep++; continuation.CandidateIndex = candidatesEvaluatedThisTile; if (clusterCount >= maxClusters) { _cardsBlockedByPerTileCap++; _cardsBlockedByClusterCap++; continue; } int num11 = HashCombine(tileSeed, x, z); float num12 = startX + ((float)x + 0.5f) * candidateSpacing + (Hash01(num11 ^ 0x3FD) - 0.5f) * candidateSpacing * 0.1f; float num13 = startZ + ((float)z + 0.5f) * candidateSpacing + (Hash01(num11 ^ 0xA21) - 0.5f) * candidateSpacing * 0.1f; float num14 = FlatDistance(num12, num13, _buildAnchor.x, _buildAnchor.z); if (num14 > ContinuityEnd() || num14 < ContinuityStart() || !InsideWorld(num12, num13)) { continue; } bool flag6 = num14 >= handoffFillInner && num14 <= handoffFillOuter; ForestRing forestRing = RingForDistance(num14); float num15 = Mathf.Clamp01(candidateSpacing * candidateSpacing / Mathf.Max(0.0001f, cell * cell)); if (_buildingPrimaryCoverageJob && ContinuousForestCoverageEnabled()) { num15 = Mathf.Max(num15, ContinuousCoverageGridRetention(forestRing)); } if (!flag6 && Hash01(num11 ^ 0x4805) > num15) { continue; } _forestTerrainSamplesThisFrame++; if (!_provider.TrySample(num12, num13, out var sample) || !sample.Valid) { continue; } CountBiomeCandidate(sample.Biome); float num16 = Mathf.Clamp01(sample.ForestDensity * ForestDensityMultiplier()); num16 = Mathf.Clamp01(Mathf.Max(num16, BiomeCandidateDensityFloor(sample.Biome))); bool flag7 = IsSwampBiome(sample.Biome); if (num16 < ForestDensityThreshold()) { if (!flag6 || !HandoffFillEnabled() || (_handoffFillRequiresValidForestLand.Value && !CandidateSurfaceSupported(sample))) { if (flag7) { _swampRejectedThreshold++; } continue; } num16 = Mathf.Max(num16, ForestDensityThreshold() + 0.001f); } _forestSlopeChecksThisFrame++; if (sample.SlopeDegrees >= BiomeMaxSlope(sample.Biome)) { if (flag7) { _swampRejectedSlope++; } if (_buildingPrimaryCoverageJob && ContinuousForestCoverageEnabled() && ContinuousCoverageTargetForBiome(sample.Biome) > 0f && !HasPrimaryCoverageCardWithin(num12, num13, sample.Biome, RingMaximumCoverageGap(forestRing), out var _)) { _ringCoverageSlopeRejections[(int)forestRing]++; } continue; } if (flag7) { _swampPassedDensity++; } if (num14 < _traceNearestRawCandidateDistance) { _traceNearestRawCandidateDistance = num14; } float num17 = 1f - Mathf.InverseLerp(_slopeRejectionThreshold.Value, _hardSlopeRejectionThreshold.Value, sample.SlopeDegrees); float num18 = Mathf.Clamp01(Mathf.Max(num16 * BiomeForestMultiplier(sample.Biome) * num17, BiomeCandidateDensityFloor(sample.Biome))); float num19 = 1f - Smooth01(Mathf.InverseLerp(ContinuityEnd() - 250f, ContinuityEnd(), num14)); float num20 = Mathf.Clamp01((num18 - ForestDensityThreshold()) / Mathf.Max(0.01f, 1f - ForestDensityThreshold()) * 1.65f * Mathf.Max(0.15f, num19)); bool flag8 = flag6; bool flag9 = false; if (flag8) { _handoffFillBandCandidatesSeen++; float num21 = HandoffFillCoverageTargetForBiome(sample.Biome); bool flag10 = HandoffFillEnforcesMaxGapForBiome(sample.Biome) && (float.IsNaN(_handoffFillLastRowAcceptedX) || FlatDistance(num12, num13, _handoffFillLastRowAcceptedX, _handoffFillLastRowZ) >= Mathf.Max(candidateSpacing, HandoffFillMaximumGap() - candidateSpacing * 0.25f)); if (num21 > 0f && (flag10 || Hash01(num11 ^ 0xD80F) < num21)) { flag9 = true; _handoffFillBandCandidatesForced++; } } bool flag11 = false; bool flag12 = (sample.Biome & 8) > 0; if (_buildingPrimaryCoverageJob && ContinuousForestCoverageEnabled()) { float num22 = ContinuousCoverageTargetForBiome(sample.Biome); flag11 = num22 > 0f && Hash01(num11 ^ 0x16ABD) < num22; } if (!flag9 && !flag11 && Hash01(num11 ^ 0x1FAF) > num20) { if (flag8) { RecordHandoffFillGapCandidate(sample.Biome, num12, num13); } continue; } nearestDensity = Mathf.Max(nearestDensity, num18); bool flag13 = false; int num23 = ((num18 > 0.72f) ? 3 : ((!(num18 > 0.42f)) ? 1 : 2)); if (_buildingPrimaryCoverageJob && (forestRing == ForestRing.Handoff || forestRing == ForestRing.Near)) { if ((sample.Biome & 8) != 0) { int num24 = ((_blackForestNearMinimumSubclusters != null) ? Mathf.Clamp(_blackForestNearMinimumSubclusters.Value, 1, 6) : 3); num23 = Mathf.Max(num23, num24); } else if ((sample.Biome & 1) != 0) { int num25 = ((_meadowsNearMinimumSubclusters != null) ? Mathf.Clamp(_meadowsNearMinimumSubclusters.Value, 1, 5) : 2); num23 = Mathf.Max(num23, num25); } } if (_buildingReinforcementJob) { float num26 = Mathf.Max(0f, ((_globalDistributedTreeDensity != null) ? _globalDistributedTreeDensity.Value : 1.65f) * DistributedDensityForBiome(sample.Biome)); int num27 = Mathf.Max(num23, Mathf.CeilToInt((float)num23 * num26)); _densityRequestedCards += num27; num23 = num27; } for (int i = 0; i < num23; i++) { if (clusterCount >= maxClusters) { break; } int num28 = HashCombine(num11, i, 9127); float num29 = ((i == 0) ? 0f : (Mathf.Sqrt(Hash01(num28 ^ 0x1343)) * cell * 0.32f)); float num30 = Hash01(num28 ^ 0x1E2B) * MathF.PI * 2f; float num31 = num12 + Mathf.Cos(num30) * num29; float num32 = num13 + Mathf.Sin(num30) * num29; WorldSurfaceSample worldSurfaceSample = default(WorldSurfaceSample); bool flag14 = false; bool flag15 = IsSwampBiome(sample.Biome); float num33 = num31; float num34 = num32; for (int j = 0; j < 4 && !flag14; j++) { float num35 = ((j == 0) ? num31 : (num31 + (Hash01(num28 ^ (911 + j * 53)) - 0.5f) * cell * 0.8f)); float num36 = ((j == 0) ? num32 : (num32 + (Hash01(num28 ^ (377 + j * 97)) - 0.5f) * cell * 0.8f)); if (!InsideWorld(num35, num36)) { continue; } if (j > 0 && flag15) { float num37 = FlatDistance(num35, num36, num33, num34); if (num37 > _maxSwampInlandRetryDistance.Value) { continue; } } if (_provider.TrySample(num35, num36, out var sample2) && sample2.Valid && CandidateSurfaceSupported(sample2) && sample2.SlopeDegrees < BiomeMaxSlope(sample2.Biome)) { if (j > 0 && sample2.Biome != sample.Biome) { _biomeChangedAfterRetry++; } _finalBiomeResamples++; worldSurfaceSample = sample2; num31 = num35; num32 = num36; flag14 = true; if (j > 0) { _treeSampleRetriesUsed++; } } } if (!flag14) { _swampCandidatesRejectedNoValidGround += ((flag15 && _rejectSwampCardIfNoValidGround.Value) ? 1 : 0); if (num14 < _traceNearestGroundingRejectedDistance) { _traceNearestGroundingRejectedDistance = num14; } continue; } num14 = FlatDistance(num31, num32, _buildAnchor.x, _buildAnchor.z); flag8 = num14 >= handoffFillInner && num14 <= handoffFillOuter; if (num14 < ContinuityStart() || num14 > ContinuityEnd()) { continue; } if (flag15 && _requireFinalSwampPositionRemainsSwamp.Value && !IsSwampBiome(worldSurfaceSample.Biome)) { _swampWrongBiomeRejections++; if (num14 < _traceNearestBiomeRejectedDistance) { _traceNearestBiomeRejectedDistance = num14; } continue; } ComputeCandidateCardSize(num18, worldSurfaceSample.Biome, num28, num14, out var height, out var width, out var atlasIndex); float num38 = num14 - width * 0.5f - ContinuityStart(); if (flag8 && num38 > 0.05f && num14 <= ContinuityStart() + HandoffFillMaximumGap()) { ((Vector2)(ref val))..ctor(num31 - _buildAnchor.x, num32 - _buildAnchor.z); if (((Vector2)(ref val)).sqrMagnitude > 0.0001f) { ((Vector2)(ref val)).Normalize(); float num39 = ContinuityStart() + width * 0.5f + 0.02f; float num40 = _buildAnchor.x + val.x * num39; float num41 = _buildAnchor.z + val.y * num39; if (_provider.TrySample(num40, num41, out var sample3) && sample3.Valid && CandidateSurfaceSupported(sample3) && sample3.SlopeDegrees < BiomeMaxSlope(sample3.Biome) && (!flag15 || !_requireFinalSwampPositionRemainsSwamp.Value || IsSwampBiome(sample3.Biome)) && (!flag15 || FlatDistance(num40, num41, num33, num34) <= _maxSwampInlandRetryDistance.Value)) { num31 = num40; num32 = num41; worldSurfaceSample = sample3; num14 = num39; width = ClampGroundCardWidth(width, worldSurfaceSample.Biome, CardPlacementKindForBiome(worldSurfaceSample.Biome)); _finalBiomeResamples++; } } } if (!OutsideForestExclusion(num31, num32, Mathf.Max(width * 0.5f, cell * 0.2f))) { if (num14 < _traceNearestExclusionRejectedDistance) { _traceNearestExclusionRejectedDistance = num14; } continue; } float num42 = 1f - Smooth01(Mathf.InverseLerp(TreeCardEnd() - 450f, TreeCardEnd(), num14)); float num43 = Smooth01(Mathf.InverseLerp(CanopyStart() + 50f, CanopyStart() + 450f, num14)); num43 *= 1f - Smooth01(Mathf.InverseLerp(ContinuityEnd() - 800f, ContinuityEnd(), num14)); num43 *= BiomeCanopyDensityMultiplier(worldSurfaceSample.Biome); float num44 = Mathf.Lerp(height * 0.42f, height * 0.78f, num18) * Mathf.Lerp(0.85f, 1.12f, num43); if ((Object)(object)_canopyCardMaterial == (Object)null && (Object)(object)_treeCardMaterial == (Object)null) { num44 = height; } bool flag16 = false; float num45 = SwampTreeCardEnd(worldSurfaceSample.Biome); bool flag17 = (worldSurfaceSample.Biome & 8) > 0; bool flag18 = flag17 && treePlaneBudget - treeCardCount < 2; if (treeCardCount >= treePlaneBudget || (_buildingPrimaryCoverageJob && treeCardCount >= primaryTreePlaneTargetForThisTile) || flag18) { _cardsBlockedByPlaneCap++; if (_remainingTreeCardPlaneBudget <= MaxTreeCardPlanesPerTile()) { _cardsBlockedByGlobalBudget++; } else { _cardsBlockedByPerTileCap++; } } if (HasTreeCardMaterialForBiome(worldSurfaceSample.Biome) && num14 <= num45 && treeCardCount < treePlaneBudget && (!_buildingPrimaryCoverageJob || treeCardCount < primaryTreePlaneTargetForThisTile) && CardEdgeOutsideForestExclusion(num31, num32, width) && !flag18) { int num46 = atlasIndex; float angle = Hash01(num28 ^ 0x1E2B) * MathF.PI * 2f; int num47 = ((allowOptionalCoverage && num18 > 0.55f && num42 > 0.55f) ? 3 : (allowOptionalCoverage ? 2 : ((!flag17) ? 1 : 2))); num47 = Mathf.Min(num47, treePlaneBudget - treeCardCount); ForestPlacementKind kind = CardPlacementKindForBiome(worldSurfaceSample.Biome); PlacementValidationResult validation; bool flag19 = ValidateAndLockCardToVisibleGround(worldSurfaceSample.Biome, num31, num32, width, height, num14, kind, out validation); if (!flag19 && IsSwampBiome(worldSurfaceSample.Biome)) { float num48 = Mathf.Max(0f, (_maxSwampInlandRetryDistance != null) ? _maxSwampInlandRetryDistance.Value : 12f); for (int k = 1; k <= 12; k++) { if (flag19) { break; } float num49 = num48 * Mathf.Sqrt(Hash01(num28 ^ (k * 92821 + 1709))); float num50 = Hash01(num28 ^ (k * 45677 + 811)) * MathF.PI * 2f; float num51 = num33 + Mathf.Cos(num50) * num49; float num52 = num34 + Mathf.Sin(num50) * num49; if (InsideWorld(num51, num52) && _provider != null && _provider.TrySample(num51, num52, out var sample4) && sample4.Valid && IsSwampBiome(sample4.Biome) && CandidateSurfaceSupported(sample4) && !(sample4.SlopeDegrees >= BiomeMaxSlope(sample4.Biome))) { float num53 = FlatDistance(num51, num52, _buildAnchor.x, _buildAnchor.z); if (!(num53 < ContinuityStart()) && !(num53 > ContinuityEnd()) && CardEdgeOutsideForestExclusion(num51, num52, width) && ValidateAndLockCardToVisibleGround(sample4.Biome, num51, num52, width, height, num53, kind, out validation)) { num31 = num51; num32 = num52; num14 = num53; worldSurfaceSample = sample4; flag8 = num14 >= handoffFillInner && num14 <= handoffFillOuter; flag19 = true; _treeSampleRetriesUsed++; _finalBiomeResamples++; } } } } if (!flag19 && !IsSwampBiome(worldSurfaceSample.Biome)) { if (TryRecoverTreeCardOnNearbySameBiomeLand(worldSurfaceSample.Biome, num33, num34, width, height, num28, kind, out var recoveredX, out var recoveredZ, out var recoveredDistance, out var recoveredSample, out var recoveredValidation)) { num31 = recoveredX; num32 = recoveredZ; num14 = recoveredDistance; worldSurfaceSample = recoveredSample; validation = recoveredValidation; flag8 = num14 >= handoffFillInner && num14 <= handoffFillOuter; flag19 = true; _finalBiomeResamples++; } else if (flag11 && flag12) { float radiusOverride = ((_coastalLandRecoveryRadius != null) ? _coastalLandRecoveryRadius.Value : 36f) * 2f; int attemptsOverride = ((_coastalLandRecoveryAttempts != null) ? _coastalLandRecoveryAttempts.Value : 24) * 2; if (TryRecoverTreeCardOnNearbySameBiomeLand(worldSurfaceSample.Biome, num33, num34, width, height, num28 ^ 0x11539, kind, out recoveredX, out recoveredZ, out recoveredDistance, out recoveredSample, out recoveredValidation, radiusOverride, attemptsOverride)) { num31 = recoveredX; num32 = recoveredZ; num14 = recoveredDistance; worldSurfaceSample = recoveredSample; validation = recoveredValidation; flag8 = num14 >= handoffFillInner && num14 <= handoffFillOuter; flag19 = true; _finalBiomeResamples++; _blackForestCoverageSecondPassAccepted++; } } } if (flag19) { float height2 = height; float width2 = width; int atlasIndex2 = num46; PlacementValidationResult validation2 = validation; bool flag20 = (worldSurfaceSample.Biome & 8) > 0; bool flag21 = IsMountainBiomeB(worldSurfaceSample.Biome) && _enableMountainTreeCards.Value; if (flag20) { ComposeAcceptedBlackForestCard(num18, num28, num14, out height2, out width2, out atlasIndex2); validation2 = RetargetAcceptedVisualValidation(validation, width2, height2); } else if (flag21) { ComposeAcceptedMountainCard(num18, num28, out height2, out width2, out atlasIndex2); validation2 = RetargetAcceptedVisualValidation(validation, width2, height2); } ForestChunkBuffers forestChunkBuffers = GetChunkBuffers(num31, num32, num14); GetCardBucket(worldSurfaceSample.Biome, forestChunkBuffers.TreeVertices, forestChunkBuffers.TreeUvs, forestChunkBuffers.TreeTriangles, forestChunkBuffers.MountainVertices, forestChunkBuffers.MountainUvs, forestChunkBuffers.MountainTriangles, forestChunkBuffers.SwampVertices, forestChunkBuffers.SwampUvs, forestChunkBuffers.SwampTriangles, out var targetVertices, out var targetUvs, out var targetTriangles); int goldenBudgetPlanes; bool singlePlaneLodUsed; int num54 = AddValidatedCrossedAtlasCards(targetVertices, targetUvs, targetTriangles, num31, validation2, validation2.FinalBaseY, num32, width2, height2, angle, atlasIndex2, num47, kind, worldSurfaceSample.Biome, num14, treePlaneBudget - treeCardCount, continuation.GeometryOverloadState, out goldenBudgetPlanes, out singlePlaneLodUsed); if (flag20 && num54 == 0 && (Mathf.Abs(width2 - width) > 0.001f || Mathf.Abs(height2 - height) > 0.001f)) { ConstrainAcceptedBlackForestFallback(width2, height2, out width2, out height2); PlacementValidationResult validation3 = RetargetAcceptedVisualValidation(validation, width2, height2); num54 = AddValidatedCrossedAtlasCards(targetVertices, targetUvs, targetTriangles, num31, validation3, validation3.FinalBaseY, num32, width2, height2, angle, atlasIndex2, num47, kind, worldSurfaceSample.Biome, num14, treePlaneBudget - treeCardCount, continuation.GeometryOverloadState, out goldenBudgetPlanes, out singlePlaneLodUsed); } else if (flag21 && num54 == 0) { ConstrainAcceptedMountainFallback(width2, height2, out width2, out height2); PlacementValidationResult validation4 = RetargetAcceptedVisualValidation(validation, width2, height2); num54 = AddValidatedCrossedAtlasCards(targetVertices, targetUvs, targetTriangles, num31, validation4, validation4.FinalBaseY, num32, width2, height2, angle, atlasIndex2, num47, kind, worldSurfaceSample.Biome, num14, treePlaneBudget - treeCardCount, continuation.GeometryOverloadState, out goldenBudgetPlanes, out singlePlaneLodUsed); } if ((flag20 || flag21) && num54 == 0) { BuildAcceptedSupportFallback(width, height, num46, worldSurfaceSample.Biome, out width2, out height2); PlacementValidationResult validation5 = RetargetAcceptedVisualValidation(validation, width2, height2); num54 = AddValidatedCrossedAtlasCards(targetVertices, targetUvs, targetTriangles, num31, validation5, validation5.FinalBaseY, num32, width2, height2, angle, atlasIndex2, num47, kind, worldSurfaceSample.Biome, num14, treePlaneBudget - treeCardCount, continuation.GeometryOverloadState, out goldenBudgetPlanes, out singlePlaneLodUsed); } forestChunkBuffers.RecordAtlasPlanes(targetVertices, num54, canopy: false); treeCardCount += goldenBudgetPlanes; if (flag20 && num54 > 0) { if (singlePlaneLodUsed) { _blackForestSinglePlaneCardsDetected++; } else { _blackForestCrossedCardsEmitted++; } } if (num54 > 0) { forestChunkBuffers.RecordLogicalTreeCard(singlePlaneLodUsed); stableCardRecords.Add(StableForestCardRecord(num28, num31, num32, atlasIndex2, worldSurfaceSample.Biome)); if (flag20) { RecordAcceptedBlackForestAtlasSelection(atlasIndex2, RingForDistance(num14)); } _densityAcceptedCards++; if (_buildingReinforcementJob) { _reinforcementCardsAccepted++; } else { _baselinePrimaryCardsAccepted++; } if ((worldSurfaceSample.Biome & 8) != 0) { _blackForestDensityCardsAccepted++; } else if ((worldSurfaceSample.Biome & 1) != 0) { _meadowsDensityCardsAccepted++; } else if ((worldSurfaceSample.Biome & 2) != 0) { _swampDensityCardsAccepted++; } else if ((worldSurfaceSample.Biome & 4) != 0 || (worldSurfaceSample.Biome & 0x40) != 0) { _mountainDensityCardsAccepted++; } else if ((worldSurfaceSample.Biome & 0x10) != 0) { _plainsDensityCardsAccepted++; } CountBiomeAccepted(worldSurfaceSample.Biome); flag16 = true; if (num14 < _traceNearestAcceptedCardDistance) { _traceNearestAcceptedCardDistance = num14; } if (flag8) { flag13 = true; RecordHandoffFillAcceptedCandidate(worldSurfaceSample.Biome, num31, num32); } if (_buildingPrimaryCoverageJob && ContinuousForestCoverageEnabled() && flag11) { _ringCoverageFallbackAccepted[(int)forestRing]++; if (flag12) { _blackForestCoverageFallbackAccepted++; } } } else if (_buildingReinforcementJob) { _densityRejectedCards++; } if (IsSwampBiome(worldSurfaceSample.Biome) && num54 > 0) { _closeSwampEmitted += num54; } } else { if (num14 < _traceNearestGroundingRejectedDistance) { _traceNearestGroundingRejectedDistance = num14; } if (IsSwampBiome(worldSurfaceSample.Biome)) { _swampCandidatesRejectedNoValidGround++; string text = _lastNoFloatRejectReason.ToString(); if (text.IndexOf("Water", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Coast", StringComparison.OrdinalIgnoreCase) >= 0) { _closeSwampRejectedWater++; } else { _closeSwampRejectedRoot++; } } if (_buildingPrimaryCoverageJob && ContinuousForestCoverageEnabled() && flag11) { int num55 = (int)forestRing; _ringCoverageFallbackFailed[num55]++; string text2 = _lastNoFloatRejectReason.ToString(); if (text2.IndexOf("Water", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("Coast", StringComparison.OrdinalIgnoreCase) >= 0) { _ringCoverageWaterRejections[num55]++; } else { _ringCoverageGroundingRejections[num55]++; } } } } if (allowOptionalCoverage && !flag16) { if (!_enableProxyForestMasses.Value) { _proxyAttemptsBlockedDisabled++; } else if (IsSwampBiome(worldSurfaceSample.Biome) && !_enableProxyMassesInSwamp.Value) { _proxyAttemptsBlockedSwamp++; } else { _proxyAttempts++; float width3 = Mathf.Max(num44 * 0.8f, width) / Mathf.Max(0.2f, FootprintRadiusScale(worldSurfaceSample.Biome)); width3 = ClampGroundCardWidth(width3, worldSurfaceSample.Biome, ForestPlacementKind.ProxyMass); num44 = Mathf.Min(num44, width3 / 0.8f); if (IsSwampBiome(worldSurfaceSample.Biome)) { if (width3 > _swampMaxProxyCardWidth.Value) { _swampRejectedExcessiveSpan++; } width3 = Mathf.Min(width3, _swampMaxProxyCardWidth.Value); } if (CardEdgeOutsideForestExclusion(num31, num32, width3) && ValidateAndLockCardToVisibleGround(worldSurfaceSample.Biome, num31, num32, width3, num44, num14, ForestPlacementKind.ProxyMass, out var validation6)) { ForestChunkBuffers forestChunkBuffers2 = GetChunkBuffers(num31, num32, num14); AddValidatedBiomeCluster(forestChunkBuffers2.MassVertices, forestChunkBuffers2.MassTriangles, num31, validation6, validation6.FinalBaseY, num32, width3, num44, worldSurfaceSample.Biome, num28, ForestPlacementKind.ProxyMass); } } } if (allowOptionalCoverage && HasCanopyCardMaterialForBiome(worldSurfaceSample.Biome) && num14 >= CanopyStart() && num43 > 0.25f && canopyCardCount < canopyPlaneBudget && CardEdgeOutsideForestExclusion(num31, num32, Mathf.Lerp(cell * 0.7f, cell * 1.35f, num18))) { int num56 = ChooseCanopyAtlasIndex(worldSurfaceSample.Biome, num28); float num57 = Hash01(num28 ^ 0x13F3) * MathF.PI * 2f; float width4 = Mathf.Lerp(cell * 0.7f, cell * 1.35f, num18); width4 = ClampGroundCardWidth(width4, worldSurfaceSample.Biome, ForestPlacementKind.CanopyCard); if (IsSwampBiome(worldSurfaceSample.Biome)) { if (width4 > _swampMaxCanopyCardWidth.Value) { _swampRejectedExcessiveSpan++; } width4 = Mathf.Min(width4, _swampMaxCanopyCardWidth.Value); } float num58 = Mathf.Lerp(10f, 20f, num18); if (ValidateAndLockCardToVisibleGround(worldSurfaceSample.Biome, num31, num32, width4, num58, num14, ForestPlacementKind.CanopyCard, out var validation7)) { ForestChunkBuffers forestChunkBuffers3 = GetChunkBuffers(num31, num32, num14); GetCardBucket(worldSurfaceSample.Biome, forestChunkBuffers3.CanopyVertices, forestChunkBuffers3.CanopyUvs, forestChunkBuffers3.CanopyTriangles, forestChunkBuffers3.MountainVertices, forestChunkBuffers3.MountainUvs, forestChunkBuffers3.MountainTriangles, forestChunkBuffers3.SwampVertices, forestChunkBuffers3.SwampUvs, forestChunkBuffers3.SwampTriangles, out var targetVertices2, out var targetUvs2, out var targetTriangles2); int num59 = AddValidatedAtlasCard(targetVertices2, targetUvs2, targetTriangles2, num31, validation7, validation7.FinalBaseY, num32, width4, num58, num57, num56, ForestPlacementKind.CanopyCard, worldSurfaceSample.Biome, num14, canopyPlaneBudget - canopyCardCount); forestChunkBuffers3.RecordAtlasPlanes(targetVertices2, num59, canopy: true); canopyCardCount += num59; if (num59 > 0 && num14 >= CanopyStart() + 1000f && num18 > 0.72f && canopyCardCount < canopyPlaneBudget) { float num60 = num31 + Mathf.Cos(num57 + 1.7f) * width4 * 0.22f; float num61 = num32 + Mathf.Sin(num57 + 1.7f) * width4 * 0.22f; float num62 = FlatDistance(num60, num61, _buildAnchor.x, _buildAnchor.z); WorldSurfaceSample sample5 = default(WorldSurfaceSample); bool flag22 = _provider != null && _provider.TrySample(num60, num61, out sample5) && sample5.Valid; Biome val2 = (flag22 ? sample5.Biome : worldSurfaceSample.Biome); if (flag22 && CardEdgeOutsideForestExclusion(num60, num61, width4 * 0.82f) && ValidateAndLockCardToVisibleGround(val2, num60, num61, width4 * 0.82f, num58 * 0.88f, num62, ForestPlacementKind.FillCard, out var validation8)) { ForestChunkBuffers forestChunkBuffers4 = GetChunkBuffers(num60, num61, num62); GetCardBucket(val2, forestChunkBuffers4.CanopyVertices, forestChunkBuffers4.CanopyUvs, forestChunkBuffers4.CanopyTriangles, forestChunkBuffers4.MountainVertices, forestChunkBuffers4.MountainUvs, forestChunkBuffers4.MountainTriangles, forestChunkBuffers4.SwampVertices, forestChunkBuffers4.SwampUvs, forestChunkBuffers4.SwampTriangles, out var targetVertices3, out var targetUvs3, out var targetTriangles3); int num63 = AddValidatedAtlasCard(targetVertices3, targetUvs3, targetTriangles3, num60, validation8, validation8.FinalBaseY, num61, width4 * 0.82f, num58 * 0.88f, num57 + 1.2f, (num56 + 1) & 3, ForestPlacementKind.FillCard, val2, num62, canopyPlaneBudget - canopyCardCount); forestChunkBuffers4.RecordAtlasPlanes(targetVertices3, num63, canopy: true); canopyCardCount += num63; if (num63 > 0 && val2 != worldSurfaceSample.Biome) { _finalBiomeResamples++; } } } } } clusterCount++; } if (flag6 && flag13) { _handoffFillBandCandidatesFilled++; } } } List chunkMeshSets = new List(); foreach (KeyValuePair<(int, int, int, int), ForestChunkBuffers> item in chunkBuffers) { ForestChunkBuffers buffers = item.Value; if (buffers.MassTriangles.Count == 0 && buffers.TreeTriangles.Count == 0 && buffers.CanopyTriangles.Count == 0 && buffers.MountainTriangles.Count == 0 && buffers.SwampTriangles.Count == 0) { ReturnForestChunkBuffers(buffers); continue; } string suffix = tileX + "_" + tileZ + "_" + Mathf.RoundToInt(buffers.ChunkSize) + "_" + buffers.ChunkX + "_" + buffers.ChunkZ + "_s" + buffers.Shard; Vector3 chunkOrigin = new Vector3((float)buffers.ChunkX * buffers.ChunkSize, 0f, (float)buffers.ChunkZ * buffers.ChunkSize); _forestCurrentJobStage = "mesh assembly " + tileX + "," + tileZ; IEnumerator converter = ConvertVerticesToChunkLocalResumable(buffers.MassVertices, chunkOrigin); while (converter.MoveNext()) { yield return candidatesEvaluatedThisTile; } converter.Dispose(); converter = ConvertVerticesToChunkLocalResumable(buffers.TreeVertices, chunkOrigin); while (converter.MoveNext()) { yield return candidatesEvaluatedThisTile; } converter.Dispose(); converter = ConvertVerticesToChunkLocalResumable(buffers.CanopyVertices, chunkOrigin); while (converter.MoveNext()) { yield return candidatesEvaluatedThisTile; } converter.Dispose(); converter = ConvertVerticesToChunkLocalResumable(buffers.MountainVertices, chunkOrigin); while (converter.MoveNext()) { yield return candidatesEvaluatedThisTile; } converter.Dispose(); converter = ConvertVerticesToChunkLocalResumable(buffers.SwampVertices, chunkOrigin); while (converter.MoveNext()) { yield return candidatesEvaluatedThisTile; } converter.Dispose(); while (buffers.MassTriangles.Count > 0 && (ForestGenerationFrameBudgetExpired() || _forestMeshesUploadedThisFrame >= MaximumMeshUploadsPerFrame())) { _forestDeferredUploadsTotal++; yield return candidatesEvaluatedThisTile; } Stopwatch uploadWatch = Stopwatch.StartNew(); Mesh massMesh = CreateMesh("DonegalHorizonForestMass_" + suffix, buffers.MassVertices, null, buffers.MassTriangles); uploadWatch.Stop(); _forestMeshUploadTimeThisFrameMs += (float)uploadWatch.Elapsed.TotalMilliseconds; if ((Object)(object)massMesh != (Object)null) { _forestMeshesUploadedThisFrame++; _forestLongestMeshUploadMs = Mathf.Max(_forestLongestMeshUploadMs, (float)uploadWatch.Elapsed.TotalMilliseconds); yield return candidatesEvaluatedThisTile; } while (buffers.TreeTriangles.Count > 0 && (ForestGenerationFrameBudgetExpired() || _forestMeshesUploadedThisFrame >= MaximumMeshUploadsPerFrame())) { _forestDeferredUploadsTotal++; yield return candidatesEvaluatedThisTile; } uploadWatch.Restart(); Mesh treeMesh = CreateMesh("DonegalHorizonTreeCards_" + suffix, buffers.TreeVertices, buffers.TreeUvs, buffers.TreeTriangles); uploadWatch.Stop(); _forestMeshUploadTimeThisFrameMs += (float)uploadWatch.Elapsed.TotalMilliseconds; if ((Object)(object)treeMesh != (Object)null) { _forestMeshesUploadedThisFrame++; _forestLongestMeshUploadMs = Mathf.Max(_forestLongestMeshUploadMs, (float)uploadWatch.Elapsed.TotalMilliseconds); yield return candidatesEvaluatedThisTile; } while (buffers.CanopyTriangles.Count > 0 && (ForestGenerationFrameBudgetExpired() || _forestMeshesUploadedThisFrame >= MaximumMeshUploadsPerFrame())) { _forestDeferredUploadsTotal++; yield return candidatesEvaluatedThisTile; } uploadWatch.Restart(); Mesh canopyMesh = CreateMesh("DonegalHorizonCanopy_" + suffix, buffers.CanopyVertices, buffers.CanopyUvs, buffers.CanopyTriangles); uploadWatch.Stop(); _forestMeshUploadTimeThisFrameMs += (float)uploadWatch.Elapsed.TotalMilliseconds; if ((Object)(object)canopyMesh != (Object)null) { _forestMeshesUploadedThisFrame++; _forestLongestMeshUploadMs = Mathf.Max(_forestLongestMeshUploadMs, (float)uploadWatch.Elapsed.TotalMilliseconds); yield return candidatesEvaluatedThisTile; } while (buffers.MountainTriangles.Count > 0 && (ForestGenerationFrameBudgetExpired() || _forestMeshesUploadedThisFrame >= MaximumMeshUploadsPerFrame())) { _forestDeferredUploadsTotal++; yield return candidatesEvaluatedThisTile; } uploadWatch.Restart(); Mesh mountainMesh = CreateMesh("DonegalHorizonMountainBiomeCards_" + suffix, buffers.MountainVertices, buffers.MountainUvs, buffers.MountainTriangles); uploadWatch.Stop(); _forestMeshUploadTimeThisFrameMs += (float)uploadWatch.Elapsed.TotalMilliseconds; if ((Object)(object)mountainMesh != (Object)null) { _forestMeshesUploadedThisFrame++; _forestLongestMeshUploadMs = Mathf.Max(_forestLongestMeshUploadMs, (float)uploadWatch.Elapsed.TotalMilliseconds); yield return candidatesEvaluatedThisTile; } while (buffers.SwampTriangles.Count > 0 && (ForestGenerationFrameBudgetExpired() || _forestMeshesUploadedThisFrame >= MaximumMeshUploadsPerFrame())) { _forestDeferredUploadsTotal++; yield return candidatesEvaluatedThisTile; } uploadWatch.Restart(); Mesh swampMesh = CreateMesh("DonegalHorizonSwampBiomeCards_" + suffix, buffers.SwampVertices, buffers.SwampUvs, buffers.SwampTriangles); uploadWatch.Stop(); _forestMeshUploadTimeThisFrameMs += (float)uploadWatch.Elapsed.TotalMilliseconds; if ((Object)(object)swampMesh != (Object)null) { _forestMeshesUploadedThisFrame++; _forestLongestMeshUploadMs = Mathf.Max(_forestLongestMeshUploadMs, (float)uploadWatch.Elapsed.TotalMilliseconds); yield return candidatesEvaluatedThisTile; } treeMesh = RejectAtlasMeshIfPostMeshGroundingFails(treeMesh, chunkOrigin, "tree"); canopyMesh = RejectAtlasMeshIfPostMeshGroundingFails(canopyMesh, chunkOrigin, "canopy"); mountainMesh = RejectAtlasMeshIfPostMeshGroundingFails(mountainMesh, chunkOrigin, "mountain"); swampMesh = RejectAtlasMeshIfPostMeshGroundingFails(swampMesh, chunkOrigin, "swamp"); chunkMeshSets.Add(new ForestChunkMeshSet { ChunkX = buffers.ChunkX, ChunkZ = buffers.ChunkZ, ChunkSize = buffers.ChunkSize, Shard = buffers.Shard, MassMesh = massMesh, TreeCardMesh = treeMesh, CanopyMesh = canopyMesh, MountainBiomeMesh = mountainMesh, SwampBiomeMesh = swampMesh, TreePlaneCount = (((Object)(object)treeMesh != (Object)null) ? buffers.TreeBucketTreePlanes : 0) + (((Object)(object)mountainMesh != (Object)null) ? buffers.MountainTreePlanes : 0) + (((Object)(object)swampMesh != (Object)null) ? buffers.SwampTreePlanes : 0), CanopyPlaneCount = (((Object)(object)canopyMesh != (Object)null) ? buffers.CanopyBucketCanopyPlanes : 0) + (((Object)(object)mountainMesh != (Object)null) ? buffers.MountainCanopyPlanes : 0) + (((Object)(object)swampMesh != (Object)null) ? buffers.SwampCanopyPlanes : 0), LogicalTreeCardCount = buffers.DetailedLogicalCards, CrossedLogicalTreeCardCount = buffers.DetailedCrossedLogicalCards, SinglePlaneLogicalTreeCardCount = buffers.DetailedSinglePlaneLogicalCards }); ReturnForestChunkBuffers(buffers); } _forestCandidatesProcessedThisFrame += candidatesEvaluatedThisStep; _forestGroundingSamplesThisFrame += candidatesEvaluatedThisStep; _forestMeshCardsAppendedThisFrame += Mathf.Max(0, treeCardCount + canopyCardCount - cardsAtStepStart); _forestCurrentJobCandidateIndex = candidatesEvaluatedThisTile; _forestCurrentJobCandidateTotal = targetCandidateCells; if (targetCandidateCells < totalCandidateCells) { _forestCandidateCapHitCount++; } ReportPostMeshGroundingForCompletedTile(tileX, tileZ); if (chunkMeshSets.Count == 0) { continuation.Result = null; yield break; } int num64 = 0; int num65 = 0; for (int l = 0; l < chunkMeshSets.Count; l++) { num64 += chunkMeshSets[l].TreePlaneCount; num65 += chunkMeshSets[l].CanopyPlaneCount; } continuation.Result = new ForestBuildResult { Chunks = chunkMeshSets, ClusterCount = clusterCount, TreeCardCount = treeCardCount, CanopyCardCount = num65, NearestDensity = nearestDensity, CandidateTotal = targetCandidateCells, CandidatesCompleted = candidatesEvaluatedThisTile, StableCardRecords = stableCardRecords.ToArray(), GeometryOverloadState = continuation.GeometryOverloadState }; ForestChunkBuffers GetChunkBuffers(float worldX, float worldZ, float distanceFromAnchor) { float num66; if (distanceFromAnchor <= boundaryBandOuter) { num66 = boundaryChunkSize; } else { num66 = NormalForestChunkSize(); ForestRing forestRing2 = RingForDistance(distanceFromAnchor); if (forestRing2 == ForestRing.Horizon && _forestVeryFarChunkMergeEnabled != null && _forestVeryFarChunkMergeEnabled.Value) { num66 = Mathf.Min(192f, Mathf.Max(num66, (_forestVeryFarChunkSize != null) ? _forestVeryFarChunkSize.Value : 160f)); } else if (forestRing2 == ForestRing.Far && _forestFarChunkMergeEnabled != null && _forestFarChunkMergeEnabled.Value) { num66 = Mathf.Max(num66, (_forestFarChunkSize != null) ? _forestFarChunkSize.Value : 128f); } else if (forestRing2 == ForestRing.Mid) { num66 = Mathf.Max(num66, (_midForestChunkSize != null) ? _midForestChunkSize.Value : 96f); } } int num67 = Mathf.FloorToInt(worldX / num66); int num68 = Mathf.FloorToInt(worldZ / num66); int num69 = 0; ForestChunkBuffers value; while (true) { (int, int, int, int) key = (Mathf.RoundToInt(num66), num67, num68, num69); if (!chunkBuffers.TryGetValue(key, out value)) { value = RentForestChunkBuffers(num67, num68, num66, num69, continuation); chunkBuffers[key] = value; if (num69 > 0) { ForestChunkBuffers forestChunkBuffers5 = chunkBuffers[(Mathf.RoundToInt(num66), num67, num68, num69 - 1)]; if (forestChunkBuffers5.DetailedCrossedLogicalCards >= 600 || forestChunkBuffers5.DetailedSinglePlaneLogicalCards >= 900 || forestChunkBuffers5.DetailedVertexCount >= 24000) { _rendererChunksSplitByCardLimit++; } if (forestChunkBuffers5.DetailedTriangleCount >= 20000) { _rendererChunksSplitByTriangleLimit++; } } break; } if (value.DetailedCrossedLogicalCards < 600 && value.DetailedSinglePlaneLogicalCards < 900 && value.DetailedVertexCount < 24000 && value.DetailedTriangleCount < 20000) { break; } num69++; } return value; } } private static void ConvertVerticesToChunkLocal(List vertices, Vector3 chunkOrigin) { //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_0012: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < vertices.Count; i++) { int index = i; vertices[index] -= chunkOrigin; } } private IEnumerator ConvertVerticesToChunkLocalResumable(List vertices, Vector3 chunkOrigin) { //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) if (vertices == null || vertices.Count == 0) { yield break; } int num = ((_cardsAppendedToMeshPerResumableStep != null) ? Mathf.Clamp(_cardsAppendedToMeshPerResumableStep.Value, 8, 256) : 48); if (_forestGenerationPressureMode) { num = Mathf.Min(16, num); } int verticesPerStep = Mathf.Max(32, num * 8); Stopwatch slice = Stopwatch.StartNew(); for (int i = 0; i < vertices.Count; i++) { int index = i; vertices[index] -= chunkOrigin; if ((i + 1) % verticesPerStep == 0 || slice.Elapsed.TotalMilliseconds >= (double)_forestCurrentCpuBudgetMs) { _forestMeshVerticesThisFrame += i + 1; slice.Stop(); _forestLongestMeshBatchMs = Mathf.Max(_forestLongestMeshBatchMs, (float)slice.Elapsed.TotalMilliseconds); yield return i + 1; slice.Reset(); slice.Start(); } } } private float ResolveFinalVisibleRootY(float lockedBaseY, bool rootAnchorValidated, bool groundLevelCard) { float num = (groundLevelCard ? Mathf.Max(0f, (_finalRootEmbedDepth != null) ? _finalRootEmbedDepth.Value : 0.1f) : 0f); if (rootAnchorValidated) { num += 0.01f; } return lockedBaseY - num; } private Mesh RejectAtlasMeshIfPostMeshGroundingFails(Mesh mesh, Vector3 chunkOrigin, string category) { //IL_00c4: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: 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) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_017f: 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) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_03c8: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Unknown result type (might be due to invalid IL or missing references) //IL_0400: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mesh == (Object)null) { return null; } EnsurePostMeshDiagnosticEpoch(); Vector3[] vertices = mesh.vertices; if (vertices == null || vertices.Length == 0 || (vertices.Length & 3) != 0) { RecordPostMeshGroundingViolation(category, "atlas mesh has non-quad vertex layout", 0f); return mesh; } _postMeshValidationAttempts++; _postMeshEpochMeshesChecked++; float num = ((_maxFinalGroundFloatingError != null) ? _maxFinalGroundFloatingError.Value : 0.2f); float num2 = Mathf.Max((_maxFinalGroundBurialError != null) ? _maxFinalGroundBurialError.Value : 0.6f, (_maxGroundHeightVarianceStandardCard != null) ? _maxGroundHeightVarianceStandardCard.Value : 1.5f); float waterLevel; bool flag = TryGetWaterLevel(out waterLevel); bool flag2 = false; for (int i = 0; i < vertices.Length; i += 4) { Vector3 val = vertices[i] + chunkOrigin; Vector3 val2 = vertices[i + 3] + chunkOrigin; Vector3 val3 = (val + val2) * 0.5f; Vector3[] array = (Vector3[])(object)new Vector3[3] { val, val3, val2 }; bool flag3 = false; string text = null; float error = 0f; for (int j = 0; j < array.Length; j++) { if (_provider == null || !_provider.TrySample(array[j].x, array[j].z, out var sample) || !sample.Valid) { flag3 = true; text = "authoritative water-safety sample unavailable"; continue; } bool flag4 = flag && IsAllowedShallowSwampSupport(sample.Biome, sample, waterLevel); if ((sample.Biome & 0x100) != 0 || (sample.IsWaterOrOcean && !flag4)) { flag3 = true; text = "rendered visual span reconstructed over open water"; error = num + 0.01f; } } Vector3 val4 = (val2 - val) * 0.5f; Vector2 val5 = new Vector2(val4.x, val4.z); float magnitude = ((Vector2)(ref val5)).magnitude; Vector3 val6 = (Vector3)((magnitude > 0.0001f) ? new Vector3(val4.x / magnitude, 0f, val4.z / magnitude) : Vector3.right); float num3 = Mathf.Min(magnitude, string.Equals(category, "canopy", StringComparison.OrdinalIgnoreCase) ? 2.5f : 1.75f); Vector3[] array2 = (Vector3[])(object)new Vector3[3] { val3 - val6 * num3, val3, val3 + val6 * num3 }; float[] array3 = new float[array2.Length]; float num4 = 0f; float num5 = 0f; for (int k = 0; k < array2.Length; k++) { if (_provider == null || !_provider.TrySample(array2[k].x, array2[k].z, out var sample2) || !sample2.Valid) { flag3 = true; text = "authoritative root-height sample unavailable"; continue; } bool flag5 = flag && IsAllowedShallowSwampSupport(sample2.Biome, sample2, waterLevel); if ((sample2.Biome & 0x100) != 0 || (sample2.IsWaterOrOcean && !flag5)) { flag3 = true; text = "rendered root reconstructed over open water"; error = num + 0.01f; continue; } float distance = FlatDistance(array2[k].x, array2[k].z, _buildAnchor.x, _buildAnchor.z); TryResolveRenderedGroundY(array2[k].x, array2[k].z, distance, sample2.GroundY, out var groundY, out var _); ForestPlacementKind kind = (string.Equals(category, "canopy", StringComparison.OrdinalIgnoreCase) ? ForestPlacementKind.CanopyCard : CardPlacementKindForBiome(sample2.Biome)); bool rootAnchorValidated = RootAnchorApplies(kind, sample2.Biome); float lockedBaseY = groundY + VerticalAdjustmentForBiome(sample2.Biome) - Mathf.Max(0f, BiomeSinkIntoGround(sample2.Biome)); array3[k] = ResolveFinalVisibleRootY(lockedBaseY, rootAnchorValidated, IsGroundLevelCardKind(kind)); float num6 = array2[k].y - array3[k]; float num7 = array3[k] - array2[k].y; num4 = Mathf.Max(num4, num6); num5 = Mathf.Max(num5, num7); float num8 = Mathf.Max(Mathf.Max(0f, num6), Mathf.Max(0f, num7)); _maxFinalWorldHeightmapError = Mathf.Max(_maxFinalWorldHeightmapError, num8); } if (flag3) { RecordPostMeshGroundingViolation(category, text ?? "authoritative support unavailable", error); continue; } if (num4 >= 0.0099f && num4 <= 0.5001f) { float num9 = Mathf.Max(0f, (_finalRootEmbedDepth != null) ? _finalRootEmbedDepth.Value : 0.1f); float num10 = num4 + num9; float num11 = 0f; float num12 = 0f; for (int l = 0; l < array2.Length; l++) { float num13 = array2[l].y - num10; num11 = Mathf.Max(num11, num13 - array3[l]); num12 = Mathf.Max(num12, array3[l] - num13); } if (num11 <= num + 0.0001f && num12 <= num2 + 0.0001f) { for (int m = i; m < i + 4; m++) { vertices[m].y -= num10; } flag2 = true; _postMeshRootFloatCorrections++; _postMeshRootFloatCorrectionMetres += num10; continue; } } if (num4 > num + 0.0001f || num5 > num2 + 0.0001f) { float error2 = Mathf.Max(num4, num5); RecordPostMeshGroundingViolation(category, "visible-root error float=" + num4.ToString("F2", CultureInfo.InvariantCulture) + "m burial=" + num5.ToString("F2", CultureInfo.InvariantCulture) + "m", error2); } } if (flag2) { mesh.vertices = vertices; mesh.RecalculateBounds(); } _postMeshValidatedMeshes++; return mesh; } private void EnsurePostMeshDiagnosticEpoch() { if (_postMeshDiagnosticEpoch != _forestGenerationEpoch) { _postMeshDiagnosticEpoch = _forestGenerationEpoch; _postMeshValidatorInitializedLogged = false; _postMeshEpochCompletionLogged = false; _postMeshEpochUnresolvedViolations = 0L; _postMeshEpochMeshesChecked = 0L; _postMeshTileSummariesThisEpoch.Clear(); if (!_postMeshValidatorInitializedLogged) { _postMeshValidatorInitializedLogged = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"POST-MESH GROUNDING VALIDATOR INITIALIZED"); } } } private void RecordPostMeshGroundingViolation(string category, string reason, float error) { _groundTransformOk = false; _groundTransformDetail = "VIOLATION: " + category + " post-mesh grounding: " + reason; _postValidationLiftBlockedCount++; _postMeshTrueViolations++; _postMeshEpochUnresolvedViolations++; _currentTilePostMeshViolationCount++; if (error >= _currentTilePostMeshWorstError) { _currentTilePostMeshWorstError = error; _currentTilePostMeshWorstDetail = category + ": " + reason; } if (error >= _postMeshWorstVisibleRootError) { _postMeshWorstVisibleRootError = error; _postMeshWorstViolation = category + ": " + reason; } } private void ReportPostMeshGroundingForCompletedTile(int tileX, int tileZ) { if (_currentTilePostMeshViolationCount != 0) { long item = TileKey(tileX, tileZ); if (_postMeshTileSummariesThisEpoch.Add(item) && !(Time.realtimeSinceStartup - _lastPostMeshWarningRealtime < 5f)) { _lastPostMeshWarningRealtime = Time.realtimeSinceStartup; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[New Horizons Treelines] POST-MESH GROUNDING SUMMARY tile " + tileX + "," + tileZ + ": " + _currentTilePostMeshViolationCount + " genuine visible-root violation(s); worst " + _currentTilePostMeshWorstError.ToString("F2", CultureInfo.InvariantCulture) + "m, " + _currentTilePostMeshWorstDetail + ".")); } } } private void TryReportPostMeshGroundingEpochCompletion() { if (_postMeshDiagnosticEpoch != _forestGenerationEpoch || _postMeshEpochCompletionLogged || _postMeshEpochMeshesChecked <= 0 || _activeForestBuild != null || _forestAddQueue.Count > 0 || _forestAddJobsByKey.Count > 0 || _coverageRepairQueue.Count > 0) { return; } for (int i = 0; i < _ringRepairJobsPending.Length; i++) { if (_ringRepairJobsPending[i] > 0) { return; } } _postMeshEpochCompletionLogged = true; if (_postMeshEpochUnresolvedViolations == 0L) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"POST-MESH GROUNDING VALIDATION OK"); } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)("POST-MESH GROUNDING VALIDATION COMPLETED WITH " + _postMeshEpochUnresolvedViolations + " UNRESOLVED VIOLATIONS")); } } private Mesh CreateMesh(string name, List vertices, List uvs, List triangles) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_003a: 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_0056: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) if (triangles == null || triangles.Count == 0 || vertices == null || vertices.Count == 0) { return null; } for (int i = 0; i < vertices.Count; i++) { Vector3 val = vertices[i]; if (float.IsNaN(val.x) || float.IsNaN(val.y) || float.IsNaN(val.z) || float.IsInfinity(val.x) || float.IsInfinity(val.y) || float.IsInfinity(val.z)) { _forestMeshesRejectedInvalid++; _forestMeshValidationOk = false; _forestMeshValidationViolationDetail = name + ": non-finite vertex at index " + i; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[New Horizons Treelines] FOREST MESH OUTPUT VIOLATION: " + _forestMeshValidationViolationDetail)); return null; } } Mesh val2 = new Mesh(); ((Object)val2).name = name; if (vertices.Count > 65000) { val2.indexFormat = (IndexFormat)1; } val2.SetVertices(vertices); if (uvs != null && uvs.Count == vertices.Count) { val2.SetUVs(0, uvs); } val2.SetTriangles(triangles, 0, true); bool flag = name.IndexOf("Tree", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Canopy", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Mountain", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("Swamp", StringComparison.OrdinalIgnoreCase) >= 0; if (flag && (_useNeutralAtlasNormals == null || _useNeutralAtlasNormals.Value)) { Vector3[] array = (Vector3[])(object)new Vector3[vertices.Count]; Vector4[] array2 = (Vector4[])(object)new Vector4[vertices.Count]; for (int j = 0; j < array.Length; j++) { array[j] = Vector3.up; array2[j] = new Vector4(1f, 0f, 0f, 1f); } val2.normals = array; val2.tangents = array2; } else { val2.RecalculateNormals(); } val2.RecalculateBounds(); if (flag) { Vector3[] normals = val2.normals; float num = float.MaxValue; long num2 = 0L; for (int k = 0; k < normals.Length; k++) { float magnitude = ((Vector3)(ref normals[k])).magnitude; if (magnitude < num) { num = magnitude; } if (magnitude < 0.01f) { num2++; } } if (num != float.MaxValue) { _atlasMeshMinimumNormalMagnitude = Mathf.Min(_atlasMeshMinimumNormalMagnitude, num); } _atlasMeshZeroLengthNormals += num2; if (num2 > 0) { _forestMeshValidationOk = false; _forestMeshValidationViolationDetail = name + ": " + num2 + " zero/near-zero atlas normals"; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[New Horizons Treelines] ATLAS NORMAL VIOLATION: " + _forestMeshValidationViolationDetail)); } } Bounds bounds = val2.bounds; bool flag2 = !float.IsNaN(((Bounds)(ref bounds)).size.x) && !float.IsInfinity(((Bounds)(ref bounds)).size.x) && !float.IsNaN(((Bounds)(ref bounds)).size.y) && !float.IsInfinity(((Bounds)(ref bounds)).size.y) && !float.IsNaN(((Bounds)(ref bounds)).size.z) && !float.IsInfinity(((Bounds)(ref bounds)).size.z); Vector3 size = ((Bounds)(ref bounds)).size; bool flag3 = ((Vector3)(ref size)).sqrMagnitude > 1E-07f; if (val2.vertexCount <= 0 || val2.triangles.Length == 0 || !flag2 || !flag3) { _forestMeshesRejectedInvalid++; _forestMeshValidationOk = false; _forestMeshValidationViolationDetail = name + ": vertices=" + val2.vertexCount + " triIndices=" + val2.triangles.Length + " boundsFinite=" + flag2 + " boundsNonZero=" + flag3; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[New Horizons Treelines] FOREST MESH OUTPUT VIOLATION: " + _forestMeshValidationViolationDetail)); Object.Destroy((Object)(object)val2); return null; } _forestMeshesValidated++; return val2; } private static int ChooseTreeAtlasIndex(Biome biome, int seed) { //IL_0000: 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_0005: 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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if ((biome & 8) != 0 || (biome & 4) != 0 || (biome & 0x40) != 0) { return 0; } if ((biome & 2) != 0 || (biome & 0x10) != 0) { return 3; } if (!(Hash01(seed ^ 0x10F7) < 0.55f)) { return 1; } return 2; } private bool HasTreeCardMaterialForBiome(Biome biome) { //IL_0000: 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) if (IsMountainBiome(biome) && (Object)(object)_mountainBiomeCardMaterial != (Object)null) { return true; } if (IsSwampBiome(biome) && (Object)(object)_swampBiomeCardMaterial != (Object)null) { return true; } return (Object)(object)_treeCardMaterial != (Object)null; } private bool HasCanopyCardMaterialForBiome(Biome biome) { //IL_0000: 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) if (IsMountainBiome(biome) && (Object)(object)_mountainBiomeCardMaterial != (Object)null) { return true; } if (IsSwampBiome(biome) && (Object)(object)_swampBiomeCardMaterial != (Object)null) { return true; } return (Object)(object)_canopyCardMaterial != (Object)null; } private void GetCardBucket(Biome biome, List mixedVertices, List mixedUvs, List mixedTriangles, List mountainVertices, List mountainUvs, List mountainTriangles, List swampVertices, List swampUvs, List swampTriangles, out List targetVertices, out List targetUvs, out List targetTriangles) { //IL_0000: 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) if (IsMountainBiome(biome) && (Object)(object)_mountainBiomeCardMaterial != (Object)null) { targetVertices = mountainVertices; targetUvs = mountainUvs; targetTriangles = mountainTriangles; } else if (IsSwampBiome(biome) && (Object)(object)_swampBiomeCardMaterial != (Object)null) { targetVertices = swampVertices; targetUvs = swampUvs; targetTriangles = swampTriangles; } else { targetVertices = mixedVertices; targetUvs = mixedUvs; targetTriangles = mixedTriangles; } } private static bool IsMountainBiome(Biome biome) { //IL_0000: 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_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if ((biome & 4) == 0) { return (biome & 0x40) > 0; } return true; } private static ForestPlacementKind CardPlacementKindForBiome(Biome biome) { //IL_0000: 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_0005: 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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) if ((biome & 2) != 0 || (biome & 4) != 0 || (biome & 0x40) != 0 || (biome & 0x10) != 0) { return ForestPlacementKind.BiomeCard; } return ForestPlacementKind.TreeCard; } private static int ChooseCanopyAtlasIndex(Biome biome, int seed) { //IL_0000: 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_0005: 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_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_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_001c: Unknown result type (might be due to invalid IL or missing references) if ((biome & 8) != 0 || (biome & 4) != 0 || (biome & 0x40) != 0) { return 0; } if ((biome & 2) != 0) { return 2; } if ((biome & 0x10) != 0) { return 3; } if (!(Hash01(seed ^ 0x1421) < 0.5f)) { return 1; } return 2; } private static bool SameForestBiomeFamily(Biome original, Biome candidate) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_001f: 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_0025: Invalid comparison between Unknown and I4 //IL_003b: 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) Biome[] array = new Biome[8]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); Biome[] array2 = (Biome[])(object)array; for (int i = 0; i < array2.Length; i++) { bool flag = (original & array2[i]) > 0; bool flag2 = (candidate & array2[i]) > 0; if (flag || flag2) { return flag && flag2; } } return original == candidate; } private bool TryRecoverTreeCardOnNearbySameBiomeLand(Biome originalBiome, float originalX, float originalZ, float width, float height, int seed, ForestPlacementKind kind, out float recoveredX, out float recoveredZ, out float recoveredDistance, out WorldSurfaceSample recoveredSample, out PlacementValidationResult recoveredValidation, float radiusOverride = -1f, int attemptsOverride = -1) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) recoveredX = originalX; recoveredZ = originalZ; recoveredDistance = FlatDistance(originalX, originalZ, _buildAnchor.x, _buildAnchor.z); recoveredSample = default(WorldSurfaceSample); recoveredValidation = PlacementValidationResult.Invalid(kind, GroundRejectReason.Other); if (_enableCoastalLandRecovery != null && !_enableCoastalLandRecovery.Value) { return false; } if (_provider == null || !_provider.IsReady || IsSwampBiome(originalBiome)) { return false; } _coastalLandRecoverySearches++; int num = ((attemptsOverride > 0) ? Mathf.Clamp(attemptsOverride, 4, 128) : ((_coastalLandRecoveryAttempts != null) ? Mathf.Clamp(_coastalLandRecoveryAttempts.Value, 4, 64) : 24)); float num2 = ((radiusOverride > 0f) ? Mathf.Clamp(radiusOverride, 8f, 160f) : ((_coastalLandRecoveryRadius != null) ? Mathf.Clamp(_coastalLandRecoveryRadius.Value, 8f, 80f) : 36f)); float num3 = Hash01(seed ^ 0x4D51) * MathF.PI * 2f; bool flag = false; float num4 = float.NegativeInfinity; for (int i = 0; i < num; i++) { float num5 = ((float)i + 1f) / (float)num; float num6 = num2 * Mathf.Sqrt(num5); float num7 = num3 + (float)i * 2.3999631f; float num8 = originalX + Mathf.Cos(num7) * num6; float num9 = originalZ + Mathf.Sin(num7) * num6; if (!InsideWorld(num8, num9) || !_provider.TrySample(num8, num9, out var sample) || !sample.Valid || sample.IsWaterOrOcean || (sample.Biome & 0x100) != 0 || !SameForestBiomeFamily(originalBiome, sample.Biome) || !CandidateSurfaceSupported(sample) || sample.SlopeDegrees >= BiomeMaxSlope(sample.Biome)) { continue; } float num10 = FlatDistance(num8, num9, _buildAnchor.x, _buildAnchor.z); if (!(num10 < ContinuityStart()) && !(num10 > ContinuityEnd()) && CardEdgeOutsideForestExclusion(num8, num9, width) && ValidateAndLockCardToVisibleGround(sample.Biome, num8, num9, width, height, num10, kind, out var validation)) { float num11 = Mathf.Clamp01(sample.ForestDensity * ForestDensityMultiplier()); float num12 = num6 / Mathf.Max(1f, num2); float num13 = Mathf.Clamp01(sample.SlopeDegrees / Mathf.Max(1f, BiomeMaxSlope(sample.Biome))); float num14 = num11 * 2f - num12 * 0.45f - num13 * 0.25f; if (!flag || num14 > num4) { flag = true; num4 = num14; recoveredX = num8; recoveredZ = num9; recoveredDistance = num10; recoveredSample = sample; recoveredValidation = validation; } } } if (flag) { _coastalLandRecoveryAccepted++; } return flag; } private bool ShouldUseFarSinglePlaneLod(float distance, ViewFacingForestOverloadState geometryState) { ForestRing forestRing = RingForDistance(distance); if (forestRing == ForestRing.Handoff || forestRing == ForestRing.Near) { return false; } bool flag = _viewFacingForestOverloadGuardSafetyValid && _enableViewFacingForestOverloadGuard != null && _enableViewFacingForestOverloadGuard.Value; if (forestRing == ForestRing.Mid) { if (flag && geometryState == ViewFacingForestOverloadState.Hard) { return distance >= 1200f; } return false; } bool flag2 = _enableFarSinglePlaneLod != null && _enableFarSinglePlaneLod.Value; bool flag3 = flag && geometryState != ViewFacingForestOverloadState.Normal; switch (forestRing) { case ForestRing.Far: if (!flag3) { if (flag2) { return distance >= ((_farSinglePlaneLodStartDistance != null) ? _farSinglePlaneLodStartDistance.Value : 1400f); } return false; } return true; case ForestRing.Horizon: if (!flag3) { if (flag2) { return distance >= ((_horizonSinglePlaneLodStartDistance != null) ? _horizonSinglePlaneLodStartDistance.Value : 2600f); } return false; } return true; default: return false; } } private float PlayerReferenceFacingPlaneAngle(float x, float z, float fallbackAngle) { float num = _buildAnchor.x - x; float num2 = _buildAnchor.z - z; if (num * num + num2 * num2 < 0.01f) { return fallbackAngle; } return Mathf.Atan2(num2, num) + MathF.PI / 2f; } private int AddValidatedCrossedAtlasCards(List vertices, List uvs, List triangles, float x, PlacementValidationResult validation, float requestedBaseY, float z, float width, float height, float angle, int atlasIndex, int planes, ForestPlacementKind kind, Biome biome, float distance, int maximumOutputPlanes, ViewFacingForestOverloadState geometryState, out int goldenBudgetPlanes, out bool singlePlaneLodUsed) { //IL_003f: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0185: 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_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Clamp(planes, 1, 3); int num2 = Mathf.Max(1, maximumOutputPlanes); goldenBudgetPlanes = 0; singlePlaneLodUsed = false; if (ShouldUseFarSinglePlaneLod(distance, geometryState)) { float angle2 = PlayerReferenceFacingPlaneAngle(x, z, angle); PlacementValidationResult validation2 = validation; if ((!RootAnchorApplies(kind, biome) || ValidateAndLockTrunkAnchor(ref validation2, biome, x, z, width, height, angle2, distance, kind)) && TryGetGuardedMeshBase(validation2, requestedBaseY, kind, atlasCard: true, out var baseY)) { int num3 = TryAddAtlasCard(vertices, uvs, triangles, x, validation2, baseY, z, width, height, angle2, atlasIndex, kind, biome, manageSpatialDuplicate: true, num2); if (num3 > 0) { goldenBudgetPlanes = Mathf.Min(num, num2); singlePlaneLodUsed = true; _farLodLogicalCards++; _farLodSinglePlaneCardsRendered++; long num4 = (long)Math.Max(0, goldenBudgetPlanes - num3) * 2L; _farLodTrianglesAvoided += num4; float num5 = width * VisibleBoundsForCard(kind, biome, atlasIndex).WidthFraction; _farLodAlphaTestedAreaAvoided += (float)Math.Max(0, goldenBudgetPlanes - num3) * num5 * height; RecordDebugCardBase(kind, x, baseY, z, num5, height); return num3; } } } int num6 = 0; bool flag = false; int num7 = 2; int num8 = Mathf.Max(2, num2); for (int i = 0; i < num7; i++) { if (num6 >= num8) { break; } float angle3 = angle + (float)i * MathF.PI * 0.5f; PlacementValidationResult validation3 = validation; if ((!RootAnchorApplies(kind, biome) || ValidateAndLockTrunkAnchor(ref validation3, biome, x, z, width, height, angle3, distance, kind)) && TryGetGuardedMeshBase(validation3, requestedBaseY, kind, atlasCard: true, out var baseY2)) { int num9 = TryAddAtlasCard(vertices, uvs, triangles, x, validation3, baseY2, z, width, height, angle3, atlasIndex, kind, biome, !flag, num8 - num6); if (num9 > 0) { num6 += num9; flag = true; RecordDebugCardBase(kind, x, baseY2, z, width, height); } } } goldenBudgetPlanes = ((num6 > 0) ? Mathf.Min(num, num2) : 0); if (num6 > 0) { _farLodLogicalCards++; _farLodCrossedCardsRendered++; } return num6; } private int AddValidatedAtlasCard(List vertices, List uvs, List triangles, float x, PlacementValidationResult validation, float requestedBaseY, float z, float width, float height, float angle, int atlasIndex, ForestPlacementKind kind, Biome biome, float distance, int maximumOutputPlanes) { //IL_0003: 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_0050: Unknown result type (might be due to invalid IL or missing references) if (RootAnchorApplies(kind, biome) && !ValidateAndLockTrunkAnchor(ref validation, biome, x, z, width, height, angle, distance, kind)) { return 0; } int num = 0; if (TryGetGuardedMeshBase(validation, requestedBaseY, kind, atlasCard: true, out var baseY)) { num = TryAddAtlasCard(vertices, uvs, triangles, x, validation, baseY, z, width, height, angle, atlasIndex, kind, biome, manageSpatialDuplicate: true, maximumOutputPlanes); if (num > 0) { RecordDebugCardBase(kind, x, baseY, z, width, height); } } return num; } private void AddValidatedBiomeCluster(List vertices, List triangles, float x, PlacementValidationResult validation, float requestedBaseY, float z, float width, float height, Biome biome, int seed, ForestPlacementKind kind) { //IL_0034: 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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) if (!TryGetGuardedMeshBase(validation, requestedBaseY, kind, atlasCard: false, out var baseY)) { return; } _groundCardsConsidered++; float num = ResolveFinalVisibleRootY(baseY, rootAnchorValidated: false, groundLevelCard: true); if (!ValidateFinalGroundFootprint(x, z, num, width, biome, validation.ValidatedDistance, out var minGroundY, out var maxGroundY)) { RegisterGroundCardFinalReject(biome, x, z); return; } float num2 = ((!(width > 10f)) ? ((_maxGroundHeightVarianceStandardCard != null) ? _maxGroundHeightVarianceStandardCard.Value : 1.5f) : ((_maxGroundHeightVarianceLargeCard != null) ? _maxGroundHeightVarianceLargeCard.Value : 0.75f)); if (maxGroundY - minGroundY > num2) { _groundCardsRejectedHeightVariance++; return; } if (IsGroundCardSpatialDuplicate(x, z, num, width, out var _)) { _groundCardsDuplicatesSuppressed++; return; } RegisterGroundCardSpatialRecord(x, z, num, width, kind, biome); AddBiomeCluster(vertices, triangles, x, num, z, height, biome, seed); _groundCardsAccepted++; RecordDebugCardBase(kind, x, num, z, width, height); } private bool TryGetGuardedMeshBase(PlacementValidationResult validation, float requestedBaseY, ForestPlacementKind kind, bool atlasCard, out float baseY) { baseY = 0f; if (!validation.IsValid || !validation.GroundLocked || !validation.VisibleLandSupported) { RegisterMeshGuardReject(kind, atlasCard, !validation.IsValid); return false; } if (validation.CardKind != kind) { RegisterMeshGuardReject(kind, atlasCard, validationMissing: true); return false; } baseY = EnforceNoPostLockLift(validation, requestedBaseY, kind); return true; } private float EnforceNoPostLockLift(PlacementValidationResult validation, float requestedBaseY, ForestPlacementKind kind) { if (validation.RootAnchorValidated && Mathf.Abs(requestedBaseY - validation.RootPreLockBaseY) <= 0.001f) { return validation.FinalBaseY; } if (requestedBaseY > validation.FinalBaseY + 0.0101f) { _postLockLiftDetectedCount++; _postValidationLiftBlockedCount++; if (validation.RootAnchorValidated) { _treeCardPostRootLiftBlocked++; } return validation.FinalBaseY; } return requestedBaseY; } private void RegisterMeshGuardReject(ForestPlacementKind kind, bool atlasCard, bool validationMissing) { if (atlasCard) { _addAtlasCardBlockedCount++; } if (IsTreeBiomeKind(kind)) { _treeBiomeRejectedAfterMeshGuard++; if (validationMissing) { _treeBiomeRejectedValidationMissing++; } } } private void RecordDebugCardBase(ForestPlacementKind kind, float x, float baseY, float z, float width, float height) { if (_debugDrawCardBases != null && _debugDrawCardBases.Value && _debugCardBaseLogsThisRebuild < 40) { _debugCardBaseLogsThisRebuild++; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Card base " + kind.ToString() + " pos=(" + x.ToString("F1", CultureInfo.InvariantCulture) + "," + baseY.ToString("F2", CultureInfo.InvariantCulture) + "," + z.ToString("F1", CultureInfo.InvariantCulture) + ") width=" + width.ToString("F1", CultureInfo.InvariantCulture) + " height=" + height.ToString("F1", CultureInfo.InvariantCulture) + ".")); } } private float MinimumWidthToHeightRatioForBiome(Biome biome, bool isMountainCard, out bool enforceRatioFloor) { //IL_0000: 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) if ((biome & 8) != 0) { enforceRatioFloor = true; if (_blackForestMinimumWidthToHeightRatio == null) { return 0.58f; } return _blackForestMinimumWidthToHeightRatio.Value; } if (isMountainCard) { enforceRatioFloor = true; if (_mountainMinimumWidthToHeightRatio == null) { return 0.42f; } return _mountainMinimumWidthToHeightRatio.Value; } enforceRatioFloor = false; return 0f; } private unsafe int TryAddAtlasCard(List vertices, List uvs, List triangles, float x, PlacementValidationResult validation, float ground, float z, float width, float height, float angle, int atlasIndex, ForestPlacementKind kind, Biome biome, bool manageSpatialDuplicate, int maximumOutputPlanes) { //IL_0023: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Invalid comparison between Unknown and I4 //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0ce9: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0e19: Unknown result type (might be due to invalid IL or missing references) //IL_0e26: Unknown result type (might be due to invalid IL or missing references) //IL_0e2b: Unknown result type (might be due to invalid IL or missing references) //IL_0f3c: Unknown result type (might be due to invalid IL or missing references) //IL_0f41: Unknown result type (might be due to invalid IL or missing references) //IL_0f43: Unknown result type (might be due to invalid IL or missing references) //IL_0f4e: Unknown result type (might be due to invalid IL or missing references) //IL_0f53: Unknown result type (might be due to invalid IL or missing references) //IL_0f55: Unknown result type (might be due to invalid IL or missing references) //IL_0f60: Unknown result type (might be due to invalid IL or missing references) //IL_0f65: Unknown result type (might be due to invalid IL or missing references) //IL_0f67: Unknown result type (might be due to invalid IL or missing references) //IL_0f72: Unknown result type (might be due to invalid IL or missing references) //IL_0f77: Unknown result type (might be due to invalid IL or missing references) //IL_0f79: Unknown result type (might be due to invalid IL or missing references) //IL_0f7e: Unknown result type (might be due to invalid IL or missing references) //IL_0f80: Unknown result type (might be due to invalid IL or missing references) //IL_0f82: Unknown result type (might be due to invalid IL or missing references) //IL_0f84: Unknown result type (might be due to invalid IL or missing references) //IL_0e47: Unknown result type (might be due to invalid IL or missing references) //IL_0e4c: Unknown result type (might be due to invalid IL or missing references) //IL_0e4e: Unknown result type (might be due to invalid IL or missing references) //IL_0e53: Unknown result type (might be due to invalid IL or missing references) //IL_0e5e: Unknown result type (might be due to invalid IL or missing references) //IL_0e63: Unknown result type (might be due to invalid IL or missing references) //IL_0e65: Unknown result type (might be due to invalid IL or missing references) //IL_0e6a: Unknown result type (might be due to invalid IL or missing references) //IL_0e8f: Unknown result type (might be due to invalid IL or missing references) //IL_0e94: Unknown result type (might be due to invalid IL or missing references) //IL_0e96: Unknown result type (might be due to invalid IL or missing references) //IL_0e9b: Unknown result type (might be due to invalid IL or missing references) //IL_0ea6: Unknown result type (might be due to invalid IL or missing references) //IL_0eab: Unknown result type (might be due to invalid IL or missing references) //IL_0ead: Unknown result type (might be due to invalid IL or missing references) //IL_0eb2: Unknown result type (might be due to invalid IL or missing references) //IL_0ed1: Unknown result type (might be due to invalid IL or missing references) //IL_0ed3: Unknown result type (might be due to invalid IL or missing references) //IL_0eda: Unknown result type (might be due to invalid IL or missing references) //IL_0edf: Unknown result type (might be due to invalid IL or missing references) //IL_0ee1: Unknown result type (might be due to invalid IL or missing references) //IL_0ee3: Unknown result type (might be due to invalid IL or missing references) //IL_0eea: Unknown result type (might be due to invalid IL or missing references) //IL_0eef: Unknown result type (might be due to invalid IL or missing references) //IL_0ef4: Unknown result type (might be due to invalid IL or missing references) //IL_0ef6: Unknown result type (might be due to invalid IL or missing references) //IL_0ef8: Unknown result type (might be due to invalid IL or missing references) //IL_0efa: Unknown result type (might be due to invalid IL or missing references) //IL_0efc: Unknown result type (might be due to invalid IL or missing references) //IL_0efe: Unknown result type (might be due to invalid IL or missing references) //IL_0f00: Unknown result type (might be due to invalid IL or missing references) //IL_0f02: Unknown result type (might be due to invalid IL or missing references) //IL_0f0c: Unknown result type (might be due to invalid IL or missing references) //IL_0f0e: Unknown result type (might be due to invalid IL or missing references) //IL_0f10: Unknown result type (might be due to invalid IL or missing references) //IL_0f12: Unknown result type (might be due to invalid IL or missing references) //IL_0f14: Unknown result type (might be due to invalid IL or missing references) //IL_0f16: Unknown result type (might be due to invalid IL or missing references) //IL_0f18: Unknown result type (might be due to invalid IL or missing references) //IL_0f1a: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_09f7: Unknown result type (might be due to invalid IL or missing references) //IL_08f0: Unknown result type (might be due to invalid IL or missing references) //IL_092e: Unknown result type (might be due to invalid IL or missing references) //IL_095d: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_0bc2: Unknown result type (might be due to invalid IL or missing references) //IL_0ad0: Unknown result type (might be due to invalid IL or missing references) //IL_0be3: Unknown result type (might be due to invalid IL or missing references) //IL_0be6: Unknown result type (might be due to invalid IL or missing references) //IL_0b99: Unknown result type (might be due to invalid IL or missing references) //IL_0766: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_05e0: Unknown result type (might be due to invalid IL or missing references) //IL_05f7: Unknown result type (might be due to invalid IL or missing references) //IL_0623: Unknown result type (might be due to invalid IL or missing references) //IL_065f: Unknown result type (might be due to invalid IL or missing references) if (!IsPlacementValidationCurrentAndMatching(validation, x, z, width, height, kind)) { RegisterMeshGuardReject(kind, atlasCard: true, validationMissing: true); return 0; } if (RootAnchorApplies(kind, biome) && !HasMatchingRootAnchorProof(validation, x, z, angle)) { RegisterRootMissingMeshGuardReject(kind); return 0; } if (ground > validation.FinalBaseY + 0.0101f) { ground = EnforceNoPostLockLift(validation, ground, kind); } if (validation.RootAnchorValidated && Mathf.Abs(ground - validation.RootLockedBaseY) > 0.001f) { _treeCardPostRootLiftBlocked++; RegisterMeshGuardReject(kind, atlasCard: true, validationMissing: false); return 0; } AtlasVisibleBounds bounds = VisibleBoundsForCard(kind, biome, atlasIndex); bool flag = (biome & 8) > 0; bool flag2 = IsMountainBiomeB(biome); bool flag3 = flag || flag2; float num = width; float num2 = Mathf.Max(0.05f, 1f - bounds.MinV); float num3 = Mathf.Clamp01(bounds.HeightFraction / num2); float num4 = (flag3 ? num : (num * bounds.WidthFraction)); float num5 = (flag3 ? height : (height * num3)); float num6 = num5; if (flag3) { width = num4; height = num5; } bool flag4 = IsGroundLevelCardKind(kind); float num7 = ResolveFinalVisibleRootY(ground, validation.RootAnchorValidated, flag4); if (validation.RootAnchorValidated) { _treeCardMeshBottomCorrected++; } bool flag5 = false; float num8 = num7; float num9 = num7; if (flag4 && (_enableStrictFinalHeightmapValidation == null || _enableStrictFinalHeightmapValidation.Value)) { _groundCardsConsidered++; float num10 = ((_maxFinalGroundFloatingError != null) ? _maxFinalGroundFloatingError.Value : 0.2f); if (IsSwampBiome(biome) && _swampMaxFinalFloatingClearance != null) { num10 = Mathf.Min(num10, _swampMaxFinalFloatingClearance.Value); } float num11 = ((_maxFinalGroundBurialError != null) ? _maxFinalGroundBurialError.Value : 0.6f); if (!ValidateFinalVisualSpanWaterSafety(x, z, width, angle, biome, kind)) { RegisterGroundCardFinalReject(biome, x, z); return 0; } float num12 = GroundSupportWidth(width, biome, kind); float burialTolerance = ((kind == ForestPlacementKind.ProxyMass) ? num11 : Mathf.Max(num11, (_maxGroundHeightVarianceStandardCard != null) ? _maxGroundHeightVarianceStandardCard.Value : 1.5f)); if (!ValidateFinalGroundSpan(x, z, num7, num12, angle, biome, num10, burialTolerance, validation.ValidatedDistance, out var minGroundY, out var maxGroundY)) { RegisterGroundCardFinalReject(biome, x, z); return 0; } if (_enableSlopeAwareCardGrounding == null || _enableSlopeAwareCardGrounding.Value) { _slopeAwareCardsTested++; bool enforceRatioFloor; float num13 = MinimumWidthToHeightRatioForBiome(biome, flag2, out enforceRatioFloor); float num14 = ((!flag2) ? ((_maxStandardFootprintVariation != null) ? _maxStandardFootprintVariation.Value : 1.25f) : ((_maxMountainFootprintVariation != null) ? _maxMountainFootprintVariation.Value : 1.75f)); float num15 = ((_maxVisibleEdgeFloatingError != null) ? _maxVisibleEdgeFloatingError.Value : 0.12f); float num16 = ((_maxVisibleEdgeBurialError != null) ? _maxVisibleEdgeBurialError.Value : 1.25f); float num17 = width; float num18 = height; float maxFloatError = 0f; float maxBurialError = 0f; float variation = 0f; bool flag6 = EvaluateVisibleEdgeGrounding(x, z, num17, angle, biome, num7, validation.ValidatedDistance, flag2, out maxFloatError, out maxBurialError, out variation) && maxFloatError <= num15 && maxBurialError <= num16 && variation <= num14; if (!flag6) { _slopeAwareEdgeFloatingDetected++; if (_enableAutomaticWidthReduction == null || _enableAutomaticWidthReduction.Value) { float num19 = ((!flag) ? ((!flag2) ? ((_minimumAutomaticWidthScale != null) ? Mathf.Clamp01(_minimumAutomaticWidthScale.Value) : 0.45f) : ((_mountainMinimumAutomaticWidthScale != null) ? Mathf.Clamp01(_mountainMinimumAutomaticWidthScale.Value) : 0.72f)) : ((_blackForestMinimumAutomaticWidthScale != null) ? Mathf.Clamp01(_blackForestMinimumAutomaticWidthScale.Value) : 0.78f)); float num20 = width * num19; float num21 = num17; float num22 = num18; for (int i = 0; i < 3; i++) { if (flag6) { break; } float num23 = num21; num21 *= 0.8f; if (num21 < num20) { num21 = num20; } if (enforceRatioFloor && num23 > 0.01f) { num22 *= num21 / num23; } if (EvaluateVisibleEdgeGrounding(x, z, num21, angle, biome, num7, validation.ValidatedDistance, flag2, out maxFloatError, out maxBurialError, out variation) && maxFloatError <= num15 && maxBurialError <= num16 && variation <= num14 && (!enforceRatioFloor || num21 / Mathf.Max(0.01f, num22) >= num13)) { num17 = num21; num18 = num22; flag6 = true; _slopeAwareWidthReduced++; if (flag) { _blackForestProportionallyReduced++; } if (flag2) { _mountainProportionallyReduced++; } } else if (num21 <= num20) { break; } } } if (!flag6 && !flag2 && (_enableSlopeCardSplitting == null || _enableSlopeCardSplitting.Value) && maximumOutputPlanes >= 2) { int num24 = ((_maximumSplitAttempts != null) ? Mathf.Clamp(_maximumSplitAttempts.Value, 1, 4) : 2); float num25 = num17; float num26 = width / Mathf.Max(0.01f, height); float num27 = Mathf.Cos(angle); float num28 = Mathf.Sin(angle); float num29 = ground - num7; for (int j = 1; j <= num24; j++) { if (flag6) { break; } float num30 = num25 * 0.5f; float num31 = (enforceRatioFloor ? (num30 / num26) : num18); float num32 = num25 * 0.25f; float x2 = x - num27 * num32; float z2 = z - num28 * num32; float x3 = x + num27 * num32; float z3 = z + num28 * num32; bool valid; float num33 = SampleSlopeAwareGroundY(x2, z2, validation.ValidatedDistance, biome, out valid); bool valid2; float num34 = SampleSlopeAwareGroundY(x3, z3, validation.ValidatedDistance, biome, out valid2); if (valid && valid2) { float num35 = num33 - num29; float num36 = num34 - num29; float maxFloatError2; float maxBurialError2; float variation2; bool flag7 = EvaluateVisibleEdgeGrounding(x2, z2, num30, angle, biome, num35, validation.ValidatedDistance, flag2, out maxFloatError2, out maxBurialError2, out variation2) && maxFloatError2 <= num15 && maxBurialError2 <= num16 && variation2 <= num14; float maxFloatError3; float maxBurialError3; float variation3; bool flag8 = EvaluateVisibleEdgeGrounding(x3, z3, num30, angle, biome, num36, validation.ValidatedDistance, flag2, out maxFloatError3, out maxBurialError3, out variation3) && maxFloatError3 <= num15 && maxBurialError3 <= num16 && variation3 <= num14; bool flag9 = !enforceRatioFloor || num30 / Mathf.Max(0.01f, num31) >= num13; if (flag7 && flag8 && flag9) { flag5 = true; num17 = num25; num18 = num31; num8 = num35; num9 = num36; maxFloatError = Mathf.Max(maxFloatError2, maxFloatError3); flag6 = true; _slopeAwareSplitAccepted++; _groundCardsSplitOnUnevenTerrain++; if (flag) { _blackForestSplitOnSlopes++; } if (flag2) { _mountainSplitOnSlopes++; } break; } } num25 *= 0.75f; } if (!flag6) { _slopeAwareRejectedAfterSplit++; } } if (!flag6) { _groundCardsRejectedHeightVariance++; if (IsPlainsBiomeB(biome)) { _plainsCardsRejectedGroundError++; } if (flag) { _blackForestRejectedTooThin++; } _lastStackedCardViolation = "visible edge grounding failed (float " + maxFloatError.ToString("F2", CultureInfo.InvariantCulture) + "m, burial " + maxBurialError.ToString("F2", CultureInfo.InvariantCulture) + "m, variation " + variation.ToString("F2", CultureInfo.InvariantCulture) + "m) at (" + x.ToString("F0", CultureInfo.InvariantCulture) + "," + z.ToString("F0", CultureInfo.InvariantCulture) + "), biome " + ((object)(*(Biome*)(&biome))/*cast due to .constrained prefix*/).ToString(); return 0; } } _slopeAwareMaxFinalEdgeError = Mathf.Max(_slopeAwareMaxFinalEdgeError, maxFloatError); width = num17; height = num18; } else { float num37 = ((!(num12 > 10f)) ? ((_maxGroundHeightVarianceStandardCard != null) ? _maxGroundHeightVarianceStandardCard.Value : 1.5f) : ((_maxGroundHeightVarianceLargeCard != null) ? _maxGroundHeightVarianceLargeCard.Value : 0.75f)); if (maxGroundY - minGroundY > num37) { if (!flag2 && (_splitLargeCardsOnUnevenTerrain == null || _splitLargeCardsOnUnevenTerrain.Value) && maximumOutputPlanes >= 2) { float visualWidth = width * 0.5f; float num38 = GroundSupportWidth(visualWidth, biome, kind); float num39 = Mathf.Cos(angle); float num40 = Mathf.Sin(angle); float num41 = width * 0.25f; float minGroundY2; float maxGroundY2; bool flag10 = ValidateFinalGroundSpan(x - num39 * num41, z - num40 * num41, num7, num38, angle, biome, num10, burialTolerance, validation.ValidatedDistance, out minGroundY2, out maxGroundY2); float minGroundY3; float maxGroundY3; bool flag11 = ValidateFinalGroundSpan(x + num39 * num41, z + num40 * num41, num7, num38, angle, biome, num10, burialTolerance, validation.ValidatedDistance, out minGroundY3, out maxGroundY3); float num42 = ((!(num38 > 10f)) ? ((_maxGroundHeightVarianceStandardCard != null) ? _maxGroundHeightVarianceStandardCard.Value : 1.5f) : ((_maxGroundHeightVarianceLargeCard != null) ? _maxGroundHeightVarianceLargeCard.Value : 0.75f)); if (flag10 && flag11 && maxGroundY2 - minGroundY2 <= num42 && maxGroundY3 - minGroundY3 <= num42) { flag5 = true; _groundCardsSplitOnUnevenTerrain++; } } if (!flag5) { _groundCardsRejectedHeightVariance++; if (IsPlainsBiomeB(biome)) { _plainsCardsRejectedGroundError++; } _lastStackedCardViolation = "height variance " + (maxGroundY - minGroundY).ToString("F2", CultureInfo.InvariantCulture) + "m at (" + x.ToString("F0", CultureInfo.InvariantCulture) + "," + z.ToString("F0", CultureInfo.InvariantCulture) + "), biome " + ((object)(*(Biome*)(&biome))/*cast due to .constrained prefix*/).ToString(); return 0; } } } bool flag12 = manageSpatialDuplicate && IsGroundDuplicateManagedCardKind(kind); if (flag12 && IsGroundCardSpatialDuplicate(x, z, num7, width, out var heightDifference)) { _groundCardsDuplicatesSuppressed++; if (IsPlainsBiomeB(biome)) { _plainsDuplicatesSuppressed++; } if (heightDifference > ((_duplicateBaseHeightDifferenceWarning != null) ? _duplicateBaseHeightDifferenceWarning.Value : 1f)) { _lastStackedCardViolation = "duplicate at (" + x.ToString("F0", CultureInfo.InvariantCulture) + "," + z.ToString("F0", CultureInfo.InvariantCulture) + ") height diff " + heightDifference.ToString("F2", CultureInfo.InvariantCulture) + "m, biome " + ((object)(*(Biome*)(&biome))/*cast due to .constrained prefix*/).ToString(); _maxBaseHeightDisagreement = Mathf.Max(_maxBaseHeightDisagreement, heightDifference); if (IsPlainsBiomeB(biome)) { _plainsStackedCardViolations++; } } return 0; } if (flag12) { RegisterGroundCardSpatialRecord(x, z, num7, width, kind, biome); } _groundCardsAccepted += ((!flag5) ? 1 : 2); if (flag12 && (biome & 8) != 0) { float num43 = (flag5 ? (width * 0.5f) : width); _blackForestFinalWidthSum += num43; _blackForestFinalHeightSum += height; _blackForestFinalCardSamples++; float num44 = num43 / Mathf.Max(0.01f, height); if (num44 < _blackForestWorstFinalRatio) { _blackForestWorstFinalRatio = num44; } } } AtlasUvs(atlasIndex, bounds, out var bottomLeft, out var topLeft, out var topRight, out var bottomRight); float num45 = Mathf.Max(0.05f, flag3 ? width : (width * bounds.WidthFraction)); float num46 = (flag3 ? 1f : num3); float num47 = (flag3 ? (width / Mathf.Max(0.1f, bounds.WidthFraction)) : width); float num48 = (flag3 ? (height / Mathf.Max(0.1f, num3)) : height); float originalArea = Mathf.Max(0f, num47 * num48); float tightenedArea = Mathf.Max(0f, num45 * height * num46); RecordAtlasTightening(atlasIndex, originalArea, tightenedArea, kind, biome); if (flag2 && manageSpatialDuplicate) { bool slopeReductionApplied = width + 0.001f < num4 || height + 0.001f < num6; float num49 = (flag5 ? (num45 * 0.5f) : num45); float num50 = height * num46; RegisterMountainSizeSample(num50, num49); RecordMountainCardDimensions(num6, num50, (_pendingMountainRequestedVisibleWidth > 0f) ? _pendingMountainRequestedVisibleWidth : num4, num49, num49 / Mathf.Max(0.01f, num50), _pendingMountainWidthCapApplied, slopeReductionApplied, _pendingMountainGenericCapApplied); } if (flag && atlasIndex == _blackForestTallPineAtlasIndex && manageSpatialDuplicate) { bool slopeReductionApplied2 = width + 0.001f < num4 || height + 0.001f < num6; float num51 = (flag5 ? (num45 * 0.5f) : num45); float num52 = height * num46; RecordBlackForestPineDimensions(num6, num52, (_pendingBlackForestRequestedVisibleWidth > 0f) ? _pendingBlackForestRequestedVisibleWidth : num4, num51, num51 / Mathf.Max(0.01f, num52), atlasIndex, _pendingBlackForestWidthCapApplied, slopeReductionApplied2, _pendingBlackForestGenericCapApplied); } Vector3 val = new Vector3(Mathf.Cos(angle), 0f, Mathf.Sin(angle)) * (num45 * 0.5f); if (flag5) { float num53 = (ground + height - num7) * num46; Vector3 bottomLeft2 = new Vector3(x, num8, z) - val; Vector3 topLeft2 = new Vector3(x, num8 + num53, z) - val; Vector3 bottomRight2 = default(Vector3); ((Vector3)(ref bottomRight2))..ctor(x, num8, z); Vector3 topRight2 = default(Vector3); ((Vector3)(ref topRight2))..ctor(x, num8 + num53, z); Vector3 bottomRight3 = new Vector3(x, num9, z) + val; Vector3 topRight3 = new Vector3(x, num9 + num53, z) + val; Vector3 bottomLeft3 = default(Vector3); ((Vector3)(ref bottomLeft3))..ctor(x, num9, z); Vector3 topLeft3 = default(Vector3); ((Vector3)(ref topLeft3))..ctor(x, num9 + num53, z); Vector2 val2 = Vector2.Lerp(bottomLeft, bottomRight, 0.5f); Vector2 val3 = Vector2.Lerp(topLeft, topRight, 0.5f); AddAtlasCutoutQuad(vertices, uvs, triangles, bottomLeft2, topLeft2, topRight2, bottomRight2, bottomLeft, topLeft, val3, val2); AddAtlasCutoutQuad(vertices, uvs, triangles, bottomLeft3, topLeft3, topRight3, bottomRight3, val2, val3, topRight, bottomRight); return 2; } float num54 = num7 + (ground + height - num7) * num46; AddAtlasCutoutQuad(vertices, uvs, triangles, new Vector3(x, num7, z) - val, new Vector3(x, num54, z) - val, new Vector3(x, num54, z) + val, new Vector3(x, num7, z) + val, bottomLeft, topLeft, topRight, bottomRight); return 1; } private bool ValidateFinalVisualSpanWaterSafety(float x, float z, float visualWidth, float angle, Biome biome, ForestPlacementKind kind) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Invalid comparison between Unknown and I4 //IL_011c: Unknown result type (might be due to invalid IL or missing references) if (_provider == null) { _lastStrictFinalRejectReason = StrictFinalRejectReason.UnsupportedRoot; return false; } float num = DetailedTreeCoastalSafetyWidth(visualWidth, biome, kind); float num2 = ((_maximumUnsupportedSpan != null) ? Mathf.Max(0.25f, _maximumUnsupportedSpan.Value) : 1.5f); int num3 = Mathf.Max(1, Mathf.CeilToInt(Mathf.Max(0.5f, num) / num2)); float num4 = num * 0.5f; float num5 = Mathf.Cos(angle); float num6 = Mathf.Sin(angle); float waterLevel; bool flag = TryGetWaterLevel(out waterLevel); for (int i = 0; i <= num3; i++) { float num7 = Mathf.Lerp(0f - num4, num4, (float)i / (float)num3); if (!_provider.TrySample(x + num5 * num7, z + num6 * num7, out var sample) || !sample.Valid) { _lastStrictFinalRejectReason = StrictFinalRejectReason.UnsupportedRoot; return false; } bool flag2 = flag && IsAllowedShallowSwampSupport(biome, sample, waterLevel); bool flag3 = (sample.Biome & 0x100) > 0; bool flag4 = sample.IsWaterOrOcean && !flag2; if ((_rejectGroundCardsOverOpenWater == null || _rejectGroundCardsOverOpenWater.Value) && (flag3 || flag4)) { if (IsSwampBiome(biome)) { _swampRejectedOceanEdge++; } _lastStrictFinalRejectReason = StrictFinalRejectReason.OpenWater; return false; } } return true; } private bool ValidateFinalGroundSpan(float x, float z, float expectedGround, float width, float angle, Biome biome, float floatTolerance, float burialTolerance, float distance, out float minGroundY, out float maxGroundY) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) minGroundY = float.MaxValue; maxGroundY = float.MinValue; float num = ((_maximumUnsupportedSpan != null) ? Mathf.Max(0.25f, _maximumUnsupportedSpan.Value) : 1.5f); int num2 = Mathf.Max(1, Mathf.CeilToInt(Mathf.Max(0.5f, width) / num)); float num3 = width * 0.5f; float num4 = Mathf.Cos(angle); float num5 = Mathf.Sin(angle); for (int i = 0; i <= num2; i++) { float num6 = Mathf.Lerp(0f - num3, num3, (float)i / (float)num2); float ex = x + num4 * num6; float ez = z + num5 * num6; if (!IsGroundCardEdgeSupported(ex, ez, expectedGround, floatTolerance, burialTolerance, biome, distance, out var sampledGroundY)) { float num7 = Mathf.Abs(expectedGround - sampledGroundY); _maxFinalWorldHeightmapError = Mathf.Max(_maxFinalWorldHeightmapError, num7); if (IsPlainsBiomeB(biome)) { _plainsMaxFinalGroundError = Mathf.Max(_plainsMaxFinalGroundError, num7); } return false; } minGroundY = Mathf.Min(minGroundY, sampledGroundY); maxGroundY = Mathf.Max(maxGroundY, sampledGroundY); float num8 = Mathf.Abs(expectedGround - sampledGroundY); _maxFinalWorldHeightmapError = Mathf.Max(_maxFinalWorldHeightmapError, num8); if (IsPlainsBiomeB(biome)) { _plainsMaxFinalGroundError = Mathf.Max(_plainsMaxFinalGroundError, num8); } } return true; } private bool ValidateFinalGroundFootprint(float x, float z, float expectedGround, float width, Biome biome, float distance, out float minGroundY, out float maxGroundY) { //IL_002b: 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) minGroundY = float.MaxValue; maxGroundY = float.MinValue; float num = ((_maxFinalGroundFloatingError != null) ? _maxFinalGroundFloatingError.Value : 0.2f); if (IsSwampBiome(biome) && _swampMaxFinalFloatingClearance != null) { num = Mathf.Min(num, _swampMaxFinalFloatingClearance.Value); } float burialTolerance = ((_maxFinalGroundBurialError != null) ? _maxFinalGroundBurialError.Value : 0.6f); for (int i = 0; i < 4; i++) { if (!ValidateFinalGroundSpan(x, z, expectedGround, width, (float)i * MathF.PI * 0.25f, biome, num, burialTolerance, distance, out var minGroundY2, out var maxGroundY2)) { return false; } minGroundY = Mathf.Min(minGroundY, minGroundY2); maxGroundY = Mathf.Max(maxGroundY, maxGroundY2); } return true; } private bool IsGroundCardEdgeSupported(float ex, float ez, float expectedGround, float floatTolerance, float burialTolerance, Biome biome, float distance, out float sampledGroundY) { //IL_005f: 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_00a0: 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_00ac: Invalid comparison between Unknown and I4 //IL_00b8: Unknown result type (might be due to invalid IL or missing references) _lastStrictFinalRejectReason = StrictFinalRejectReason.None; sampledGroundY = expectedGround; if (_provider == null) { _lastStrictFinalRejectReason = StrictFinalRejectReason.UnsupportedRoot; return false; } if (!_provider.TrySample(ex, ez, out var sample) || !sample.Valid) { _lastStrictFinalRejectReason = StrictFinalRejectReason.UnsupportedRoot; return false; } TryResolveRenderedGroundY(ex, ez, distance, sample.GroundY, out var groundY, out var _); sample.GroundY = groundY; sampledGroundY = groundY + VerticalAdjustmentForBiome(biome); if (sample.IsWaterOrOcean && (_rejectGroundCardsOverOpenWater == null || _rejectGroundCardsOverOpenWater.Value)) { float waterLevel; bool flag = TryGetWaterLevel(out waterLevel) && IsAllowedShallowSwampSupport(biome, sample, waterLevel); if ((sample.Biome & 0x100) > 0 || !flag) { if (IsSwampBiome(biome)) { _swampRejectedOceanEdge++; } _lastStrictFinalRejectReason = StrictFinalRejectReason.OpenWater; return false; } } float num = expectedGround - sampledGroundY; if (num > floatTolerance) { _lastStrictFinalRejectReason = StrictFinalRejectReason.Floating; return false; } if (0f - num > burialTolerance) { _lastStrictFinalRejectReason = StrictFinalRejectReason.Burial; return false; } _maxFinalVisibleRootErrorObserved = Mathf.Max(_maxFinalVisibleRootErrorObserved, Mathf.Abs(num)); return true; } private unsafe void RegisterGroundCardFinalReject(Biome biome, float x, float z) { //IL_006e: 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_009d: Unknown result type (might be due to invalid IL or missing references) _groundCardsRejectedFloatingOrBurial++; switch (_lastStrictFinalRejectReason) { case StrictFinalRejectReason.Floating: _groundCardsRejectedFloating++; break; case StrictFinalRejectReason.Burial: _groundCardsRejectedBurial++; break; case StrictFinalRejectReason.OpenWater: _groundCardsRejectedOpenWater++; break; default: _groundCardsRejectedUnsupportedRoot++; break; } if (IsSwampBiome(biome)) { _swampRejectedFinalFloating++; } if (IsPlainsBiomeB(biome)) { _plainsCardsRejectedGroundError++; } if (VerticalAdjustmentForBiome(biome) != 0f) { _cardsRejectedAfterVerticalCorrection++; } _lastStackedCardViolation = "final grounding reject (" + _lastStrictFinalRejectReason.ToString() + ") at (" + x.ToString("F0", CultureInfo.InvariantCulture) + "," + z.ToString("F0", CultureInfo.InvariantCulture) + "), biome " + ((object)(*(Biome*)(&biome))/*cast due to .constrained prefix*/).ToString(); } private static bool IsGroundLevelCardKind(ForestPlacementKind kind) { if (kind != ForestPlacementKind.TreeCard && kind != ForestPlacementKind.BiomeCard && kind != ForestPlacementKind.FillCard) { return kind == ForestPlacementKind.CanopyCard; } return true; } private static bool IsGroundDuplicateManagedCardKind(ForestPlacementKind kind) { if (kind != ForestPlacementKind.TreeCard && kind != ForestPlacementKind.BiomeCard) { return kind == ForestPlacementKind.FillCard; } return true; } private bool IsGroundCardSpatialDuplicate(float x, float z, float baseY, float width, out float heightDifference) { heightDifference = 0f; if (_enableCrossBiomeDuplicateRejection == null || !_enableCrossBiomeDuplicateRejection.Value) { return false; } if (_currentGroundCardOwnerTileKey == long.MinValue) { return false; } if (!_groundCardRecordsByTile.TryGetValue(_currentGroundCardOwnerTileKey, out var value) || value.Count == 0) { return false; } float num = ((_duplicateHorizontalDistanceTolerance != null) ? _duplicateHorizontalDistanceTolerance.Value : 2f); float num2 = ((_duplicateFootprintOverlapThreshold != null) ? _duplicateFootprintOverlapThreshold.Value : 0.7f); for (int i = 0; i < value.Count; i++) { GroundCardSpatialRecord groundCardSpatialRecord = value[i]; float num3 = FlatDistance(x, z, groundCardSpatialRecord.X, groundCardSpatialRecord.Z); float num4 = (groundCardSpatialRecord.Width + width) * 0.5f; float num5 = ((num4 > 0.01f) ? Mathf.Clamp01(1f - num3 / num4) : 0f); if (num3 <= num || num5 >= num2) { heightDifference = Mathf.Abs(baseY - groundCardSpatialRecord.BaseY); return true; } } return false; } private static bool IsPrimaryCoverageKind(ForestPlacementKind kind) { if (kind != ForestPlacementKind.TreeCard) { return kind == ForestPlacementKind.BiomeCard; } return true; } private bool HasPrimaryCoverageCardWithin(float x, float z, Biome biome, float maxGap, out float nearestDistance) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) if (TryFindNearestAcceptedCoverageCard(x, z, biome, maxGap, out nearestDistance)) { return nearestDistance <= maxGap; } return false; } private bool TryFindNearestAcceptedCoverageCard(float x, float z, Biome biome, float searchRadius, out float nearestDistance) { //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0128: 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_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0139: 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_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) nearestDistance = float.MaxValue; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(0f, float.MaxValue, 0f); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(0f, float.MaxValue, 0f); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(0f, float.MaxValue, 0f); int num = Mathf.Max(1, Mathf.CeilToInt(searchRadius / 16f)); int num2 = Mathf.FloorToInt(x / 16f); int num3 = Mathf.FloorToInt(z / 16f); Vector3 val4 = default(Vector3); for (int i = -num; i <= num; i++) { for (int j = -num; j <= num; j++) { if (!_primaryCoverageSpatialHash.TryGetValue((num2 + i, num3 + j), out var value)) { continue; } for (int k = 0; k < value.Count; k++) { AcceptedCoverageCardRecord acceptedCoverageCardRecord = value[k]; if (acceptedCoverageCardRecord.GenerationEpoch != _forestGenerationEpoch || !CoverageBiomesMatch(acceptedCoverageCardRecord.Biome, biome)) { continue; } float num4 = FlatDistance(x, z, acceptedCoverageCardRecord.X, acceptedCoverageCardRecord.Z); if (!(num4 > searchRadius) && !(num4 >= val3.y)) { ((Vector3)(ref val4))..ctor(acceptedCoverageCardRecord.X, num4, acceptedCoverageCardRecord.Z); if (num4 < val.y) { val3 = val2; val2 = val; val = val4; } else if (num4 < val2.y) { val3 = val2; val2 = val4; } else { val3 = val4; } } } } } if (val.y < float.MaxValue && !CoveragePathCrossesInvalidLand(x, z, val.x, val.z, biome)) { nearestDistance = val.y; } else if (val2.y < float.MaxValue && !CoveragePathCrossesInvalidLand(x, z, val2.x, val2.z, biome)) { nearestDistance = val2.y; } else if (val3.y < float.MaxValue && !CoveragePathCrossesInvalidLand(x, z, val3.x, val3.z, biome)) { nearestDistance = val3.y; } return nearestDistance < float.MaxValue; } private static bool CoverageBiomesMatch(Biome a, Biome b) { //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_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0008: Invalid comparison between Unknown and I4 if (a != b) { return (a & b) > 0; } return true; } private bool CoveragePathCrossesInvalidLand(float x0, float z0, float x1, float z1, Biome biome) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (_provider == null) { return true; } for (int i = 1; i <= 3; i++) { float num = (float)i * 0.25f; _forestTerrainSamplesThisFrame++; if (!_provider.TrySample(Mathf.Lerp(x0, x1, num), Mathf.Lerp(z0, z1, num), out var sample) || !sample.Valid || !CoverageBiomesMatch(sample.Biome, biome) || !CandidateSurfaceSupported(sample)) { return true; } } return false; } private void RegisterGroundCardSpatialRecord(float x, float z, float baseY, float width, ForestPlacementKind kind, Biome biome) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) float num = ((_duplicateHorizontalDistanceTolerance != null) ? _duplicateHorizontalDistanceTolerance.Value : 2f); float num2 = Mathf.Max(2f, num); (int, int) key = (Mathf.FloorToInt(x / num2), Mathf.FloorToInt(z / num2)); if (!_groundCardSpatialHash.TryGetValue(key, out var value)) { value = new List(); _groundCardSpatialHash[key] = value; } GroundCardSpatialRecord item = new GroundCardSpatialRecord(x, z, baseY, width, kind, biome, _forestGenerationEpoch); value.Add(item); if (_currentGroundCardOwnerTileKey != long.MinValue) { if (!_groundCardRecordsByTile.TryGetValue(_currentGroundCardOwnerTileKey, out var value2)) { value2 = new List(); _groundCardRecordsByTile[_currentGroundCardOwnerTileKey] = value2; } value2.Add(item); } } private void ActivatePrimaryCoverageRecordsForTile(long tileKey) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (!_groundCardRecordsByTile.TryGetValue(tileKey, out var value)) { return; } for (int i = 0; i < value.Count; i++) { GroundCardSpatialRecord groundCardSpatialRecord = value[i]; if (IsPrimaryCoverageKind(groundCardSpatialRecord.Kind)) { ActivatePrimaryCoverageRecord(groundCardSpatialRecord.X, groundCardSpatialRecord.Z, groundCardSpatialRecord.Biome); } } } private void ActivatePrimaryCoverageRecord(float x, float z, Biome biome) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) (int, int) key = (Mathf.FloorToInt(x / 16f), Mathf.FloorToInt(z / 16f)); if (!_primaryCoverageSpatialHash.TryGetValue(key, out var value)) { value = new List(4); _primaryCoverageSpatialHash[key] = value; } for (int i = 0; i < value.Count; i++) { AcceptedCoverageCardRecord acceptedCoverageCardRecord = value[i]; if (acceptedCoverageCardRecord.GenerationEpoch == _forestGenerationEpoch && CoverageBiomesMatch(acceptedCoverageCardRecord.Biome, biome) && Mathf.Abs(acceptedCoverageCardRecord.X - x) < 0.001f && Mathf.Abs(acceptedCoverageCardRecord.Z - z) < 0.001f) { return; } } value.Add(new AcceptedCoverageCardRecord(x, z, biome, _forestGenerationEpoch)); } private void MoveGroundCardRecordsToTile(long sourceKey, long destinationKey) { if (_groundCardRecordsByTile.TryGetValue(sourceKey, out var value) && value.Count != 0) { if (!_groundCardRecordsByTile.TryGetValue(destinationKey, out var value2)) { value2 = new List(value.Count); _groundCardRecordsByTile[destinationKey] = value2; } value2.AddRange(value); _groundCardRecordsByTile.Remove(sourceKey); } } private void DeactivateGroundCardRecordsForTile(long tileKey, bool deleteRecords) { if (!_groundCardRecordsByTile.TryGetValue(tileKey, out var value)) { return; } float num = ((_duplicateHorizontalDistanceTolerance != null) ? _duplicateHorizontalDistanceTolerance.Value : 2f); float num2 = Mathf.Max(2f, num); for (int i = 0; i < value.Count; i++) { GroundCardSpatialRecord item = value[i]; (int, int) key = (Mathf.FloorToInt(item.X / num2), Mathf.FloorToInt(item.Z / num2)); if (_groundCardSpatialHash.TryGetValue(key, out var value2)) { value2.Remove(item); if (value2.Count == 0) { _groundCardSpatialHash.Remove(key); } } if (!IsPrimaryCoverageKind(item.Kind)) { continue; } (int, int) key2 = (Mathf.FloorToInt(item.X / 16f), Mathf.FloorToInt(item.Z / 16f)); if (!_primaryCoverageSpatialHash.TryGetValue(key2, out var value3)) { continue; } for (int num3 = value3.Count - 1; num3 >= 0; num3--) { AcceptedCoverageCardRecord acceptedCoverageCardRecord = value3[num3]; if (Mathf.Abs(acceptedCoverageCardRecord.X - item.X) < 0.001f && Mathf.Abs(acceptedCoverageCardRecord.Z - item.Z) < 0.001f) { value3.RemoveAt(num3); } } if (value3.Count == 0) { _primaryCoverageSpatialHash.Remove(key2); } } if (deleteRecords) { _groundCardRecordsByTile.Remove(tileKey); } } private void ActivateGroundCardRecordsForTile(long tileKey) { //IL_010e: Unknown result type (might be due to invalid IL or missing references) if (!_groundCardRecordsByTile.TryGetValue(tileKey, out var value)) { return; } float num = ((_duplicateHorizontalDistanceTolerance != null) ? _duplicateHorizontalDistanceTolerance.Value : 2f); float num2 = Mathf.Max(2f, num); for (int i = 0; i < value.Count; i++) { GroundCardSpatialRecord item = value[i]; (int, int) key = (Mathf.FloorToInt(item.X / num2), Mathf.FloorToInt(item.Z / num2)); if (!_groundCardSpatialHash.TryGetValue(key, out var value2)) { value2 = new List(); _groundCardSpatialHash[key] = value2; } value2.Add(item); if (IsPrimaryCoverageKind(item.Kind)) { (int, int) key2 = (Mathf.FloorToInt(item.X / 16f), Mathf.FloorToInt(item.Z / 16f)); if (!_primaryCoverageSpatialHash.TryGetValue(key2, out var value3)) { value3 = new List(4); _primaryCoverageSpatialHash[key2] = value3; } value3.Add(new AcceptedCoverageCardRecord(item.X, item.Z, item.Biome, _forestGenerationEpoch)); } } } private float VisibleRootBottomTrim(ForestPlacementKind kind, Biome biome, int atlasIndex) { //IL_0019: 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_0038: 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) int num = Mathf.Clamp(atlasIndex, 0, 3); switch (kind) { case ForestPlacementKind.TreeCard: return _treeAtlasVisibleRootBottomTrim[num]; case ForestPlacementKind.BiomeCard: if (IsMountainBiome(biome) && (Object)(object)_mountainBiomeAtlasTexture != (Object)null) { return _mountainAtlasVisibleRootBottomTrim[num]; } if (IsSwampBiome(biome) && (Object)(object)_swampBiomeAtlasTexture != (Object)null) { return _swampAtlasVisibleRootBottomTrim[num]; } return _treeAtlasVisibleRootBottomTrim[num]; case ForestPlacementKind.FillCard: if (IsMountainBiome(biome) && (Object)(object)_mountainBiomeAtlasTexture != (Object)null) { return _mountainAtlasVisibleRootBottomTrim[num]; } if (IsSwampBiome(biome) && (Object)(object)_swampBiomeAtlasTexture != (Object)null) { return _swampAtlasVisibleRootBottomTrim[num]; } return _canopyAtlasVisibleRootBottomTrim[num]; default: return 0f; } } private AtlasVisibleBounds VisibleBoundsForCard(ForestPlacementKind kind, Biome biome, int atlasIndex) { //IL_0022: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Clamp(atlasIndex, 0, 3); AtlasVisibleBounds result; switch (kind) { case ForestPlacementKind.TreeCard: result = _treeAtlasVisibleBounds[num]; break; case ForestPlacementKind.BiomeCard: result = ((IsMountainBiome(biome) && (Object)(object)_mountainBiomeAtlasTexture != (Object)null) ? _mountainAtlasVisibleBounds[num] : ((!IsSwampBiome(biome) || !((Object)(object)_swampBiomeAtlasTexture != (Object)null)) ? _treeAtlasVisibleBounds[num] : _swampAtlasVisibleBounds[num])); break; case ForestPlacementKind.CanopyCard: case ForestPlacementKind.FillCard: result = ((IsMountainBiome(biome) && (Object)(object)_mountainBiomeAtlasTexture != (Object)null) ? _mountainAtlasVisibleBounds[num] : ((!IsSwampBiome(biome) || !((Object)(object)_swampBiomeAtlasTexture != (Object)null)) ? _canopyAtlasVisibleBounds[num] : _swampAtlasVisibleBounds[num])); break; default: result = AtlasVisibleBounds.Full; break; } if (!(result.WidthFraction > 0.0001f) || !(result.HeightFraction > 0.0001f)) { return AtlasVisibleBounds.Full; } return result; } private bool UsesMixedTreeAtlas(ForestPlacementKind kind, Biome biome) { //IL_000b: 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) switch (kind) { case ForestPlacementKind.TreeCard: return true; default: return false; case ForestPlacementKind.BiomeCard: if (IsMountainBiome(biome) && (Object)(object)_mountainBiomeAtlasTexture != (Object)null) { return false; } if (IsSwampBiome(biome) && (Object)(object)_swampBiomeAtlasTexture != (Object)null) { return false; } return true; } } private void RecordAtlasTightening(int atlasIndex, float originalArea, float tightenedArea, ForestPlacementKind kind, Biome biome) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) if (UsesMixedTreeAtlas(kind, biome)) { int num = Mathf.Clamp(atlasIndex, 0, 3); _atlasOriginalQuadAreaSum += originalArea; _atlasTightenedQuadAreaSum += tightenedArea; _atlasTightenedPlaneSamples++; _atlasOriginalAreaByCell[num] += originalArea; _atlasTightenedAreaByCell[num] += tightenedArea; _atlasAreaSamplesByCell[num]++; } } private static void AtlasUvs(int atlasIndex, AtlasVisibleBounds bounds, out Vector2 bottomLeft, out Vector2 topLeft, out Vector2 topRight, out Vector2 bottomRight) { //IL_008f: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00b3: 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_00c3: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Clamp(atlasIndex, 0, 3); int num2 = num & 1; int num3 = num >> 1; float num4 = (float)num2 * 0.5f; float num5 = 1f - (float)num3 * 0.5f; float num6 = num5 - 0.5f; float num7 = num4 + Mathf.Clamp01(bounds.MinU) * 0.5f; float num8 = num4 + Mathf.Clamp01(bounds.MaxU) * 0.5f; float num9 = num6 + Mathf.Clamp01(bounds.MinV) * 0.5f; float num10 = num6 + Mathf.Clamp01(bounds.MaxV) * 0.5f; bottomLeft = new Vector2(num7, num9); topLeft = new Vector2(num7, num10); topRight = new Vector2(num8, num10); bottomRight = new Vector2(num8, num9); } private void UpdateVisibility(Camera camera, Vector3 playerPosition) { //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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_0074: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_07f3: Unknown result type (might be due to invalid IL or missing references) //IL_0407: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_0488: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Unknown result type (might be due to invalid IL or missing references) //IL_049e: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) //IL_04b7: Unknown result type (might be due to invalid IL or missing references) //IL_04c3: Unknown result type (might be due to invalid IL or missing references) //IL_04d4: Unknown result type (might be due to invalid IL or missing references) //IL_04da: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_0825: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_0440: Unknown result type (might be due to invalid IL or missing references) //IL_0441: Unknown result type (might be due to invalid IL or missing references) //IL_0446: Unknown result type (might be due to invalid IL or missing references) //IL_0462: Unknown result type (might be due to invalid IL or missing references) //IL_0465: Unknown result type (might be due to invalid IL or missing references) //IL_06b7: Unknown result type (might be due to invalid IL or missing references) //IL_06bc: Unknown result type (might be due to invalid IL or missing references) _nearestForestTileDistance = float.MaxValue; _nearestForestTileCenter = Vector3.zero; _nearestForestDensity = 0f; _nearestTerrainTileDistance = float.MaxValue; _nearestTerrainTileCenter = Vector3.zero; _farthestTerrainTileDistance = -1f; _farthestTerrainTileCenter = Vector3.zero; _lastMapUv = ((_provider != null) ? _provider.GetTerrainUv(playerPosition.x, playerPosition.z) : Vector2.zero); if (_provider != null && _provider.TrySample(playerPosition.x, playerPosition.z, out var sample) && sample.Valid) { _lastAnchorForestDensity = sample.ForestDensity; _lastMapAlignmentStatus = "uv " + _lastMapUv.x.ToString("F3", CultureInfo.InvariantCulture) + "," + _lastMapUv.y.ToString("F3", CultureInfo.InvariantCulture) + " forest " + _lastAnchorForestDensity.ToString("F2", CultureInfo.InvariantCulture) + " height " + sample.GroundY.ToString("F1", CultureInfo.InvariantCulture); } else { _lastAnchorForestDensity = 0f; _lastMapAlignmentStatus = "sample unavailable"; } Vector3 val = (((Object)(object)camera != (Object)null) ? ((Component)camera).transform.forward : Vector3.forward); val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { val = Vector3.forward; } ((Vector3)(ref val)).Normalize(); float num = VisualExclusionRadius(); Vector3 val3; foreach (TerrainTile value in _terrainTiles.Values) { float num2 = FlatDistance(playerPosition, value.Center); int num3; if (_enableFarTerrain.Value && num2 <= FarTerrainViewDistance() + value.Size && num2 >= num - value.Size * 0.71f) { if (CullFarTilesBehindCamera()) { Vector3 val2 = val; val3 = value.Center - playerPosition; num3 = ((Vector3.Dot(val2, ((Vector3)(ref val3)).normalized) >= _behindCameraDot.Value) ? 1 : 0); } else { num3 = 1; } } else { num3 = 0; } bool flag = (byte)num3 != 0; ((Renderer)value.Renderer).enabled = flag && (Object)(object)value.Mesh != (Object)null; if (flag && num2 < _nearestTerrainTileDistance) { _nearestTerrainTileDistance = num2; _nearestTerrainTileCenter = value.Center; } if (flag && num2 > _farthestTerrainTileDistance) { _farthestTerrainTileDistance = num2; _farthestTerrainTileCenter = value.Center; } } float num4 = ContinuityStart(); float num5 = Mathf.Max(0f, (_nearCullHysteresis != null) ? _nearCullHysteresis.Value : 8f); int num6 = 0; int num7 = 0; float num8 = float.MaxValue; bool forestHandoffOk = true; int num9 = 0; int num10 = 0; int num11 = 0; bool flag2 = true; int num12 = 0; int num13 = 0; long num14 = 0L; long num15 = 0L; long num16 = 0L; long num17 = 0L; long num18 = 0L; int num19 = 0; Array.Clear(_visibleTreeRenderersByRing, 0, _visibleTreeRenderersByRing.Length); int[] array = new int[5]; int[] array2 = new int[5]; float[] array3 = new float[5] { float.MaxValue, float.MaxValue, float.MaxValue, float.MaxValue, float.MaxValue }; float[] array4 = new float[5] { -1f, -1f, -1f, -1f, -1f }; foreach (ForestTile value2 in _forestTiles.Values) { for (int i = 0; i < value2.Chunks.Count; i++) { ForestChunk forestChunk = value2.Chunks[i]; num6++; if (flag2 && (Object)(object)forestChunk.Root != (Object)null) { val3 = forestChunk.Root.transform.position - forestChunk.CreatedWorldPosition; if (((Vector3)(ref val3)).sqrMagnitude > 0.0001f) { flag2 = false; } } float num20 = FlatDistance(playerPosition, forestChunk.Center); bool flag3 = num20 <= ContinuityEnd() + forestChunk.Size; if (flag3 && CullFarTilesBehindCamera()) { Vector3 val4 = forestChunk.Center - playerPosition; val4.y = 0f; if (((Vector3)(ref val4)).sqrMagnitude > 0.0001f) { flag3 = Vector3.Dot(val, ((Vector3)(ref val4)).normalized) >= _behindCameraDot.Value; } } Bounds worldBounds = forestChunk.WorldBounds; float bx = Mathf.Clamp(playerPosition.x, ((Bounds)(ref worldBounds)).min.x, ((Bounds)(ref worldBounds)).max.x); float bz = Mathf.Clamp(playerPosition.z, ((Bounds)(ref worldBounds)).min.z, ((Bounds)(ref worldBounds)).max.z); float num21 = FlatDistance(playerPosition.x, playerPosition.z, bx, bz); bool flag4 = (forestChunk.Enabled ? (num21 >= num4) : (num21 >= num4 + num5)); bool flag5 = flag3 && flag4; forestChunk.SetEnabled(flag5); int num22 = (int)RingForDistance(num20); array[num22]++; if (flag3 && !flag4) { num7++; } if (flag5) { num14 += forestChunk.LogicalTreeCardCount; num15 += forestChunk.CrossedLogicalTreeCardCount; num16 += forestChunk.SinglePlaneLogicalTreeCardCount; num17 += forestChunk.DetailedTriangleCount; num18 += forestChunk.DetailedVertexCount; num19 += forestChunk.DetailedRendererCount; _visibleTreeRenderersByRing[num22] += forestChunk.DetailedRendererCount; int num23 = 0; if ((Object)(object)forestChunk.TreeCardMesh != (Object)null) { num23 += forestChunk.TreeCardMesh.vertexCount / 4; } if ((Object)(object)forestChunk.CanopyMesh != (Object)null) { num23 += forestChunk.CanopyMesh.vertexCount / 4; } if ((Object)(object)forestChunk.MountainBiomeMesh != (Object)null) { num23 += forestChunk.MountainBiomeMesh.vertexCount / 4; } if ((Object)(object)forestChunk.SwampBiomeMesh != (Object)null) { num23 += forestChunk.SwampBiomeMesh.vertexCount / 4; } if (num21 <= num4 + 100f) { num12 += num23; } else if (num21 <= num4 + 350f) { num13 += num23; } array2[num22]++; if (num20 < array3[num22]) { array3[num22] = num20; } if (num20 > array4[num22]) { array4[num22] = num20; } if (num21 < num8) { num8 = num21; } if (num21 < num4 - 0.01f) { forestHandoffOk = false; } if (num20 < _nearestForestTileDistance) { _nearestForestTileDistance = num20; _nearestForestTileCenter = forestChunk.Center; _nearestForestDensity = value2.NearestDensity; } } if ((Object)(object)forestChunk.SwampBiomeMesh != (Object)null) { if (flag5) { num9++; } else if (flag3 && !flag4) { num10++; } else if (!flag3) { num11++; } } } } _forestChunkCount = num6; _forestNearCulledChunkCount = num7; _nearestEnabledForestChunkEdge = num8; _swampRenderersEnabled = num9; _swampInnerCulled = num10; _swampOuterCulled = num11; _staticPlacementOk = flag2; _forestHandoffOk = forestHandoffOk; _visibleCardQuadsHandoffTo100 = num12; _visibleCardQuadsHandoff100To350 = num13; _ringBuiltChunkCounts = array; _ringVisibleChunkCounts = array2; _ringMinVisibleDistance = array3; _ringMaxVisibleDistance = array4; _visibleDetailedLogicalCards = num14; _visibleDetailedCrossedCards = num15; _visibleDetailedSinglePlaneCards = num16; _visibleDetailedTriangles = num17; _visibleDetailedVertices = num18; _visibleDetailedTreeRenderers = num19; UpdateViewFacingForestOverloadGuard(Time.realtimeSinceStartup); if (_nearestTerrainTileDistance < float.MaxValue) { _lastTerrainTintNearestStatus = BuildTerrainTintDiagnostic(_nearestTerrainTileCenter, _nearestTerrainTileDistance); } else { _lastTerrainTintNearestStatus = "no visible terrain tile"; } if (_farthestTerrainTileDistance >= 0f) { _lastTerrainTintFarthestStatus = BuildTerrainTintDiagnostic(_farthestTerrainTileCenter, _farthestTerrainTileDistance); } else { _lastTerrainTintFarthestStatus = "no visible terrain tile"; } } private void UpdateViewFacingForestOverloadGuard(float now) { if (!_viewFacingForestOverloadGuardSafetyValid || _enableViewFacingForestOverloadGuard == null || !_enableViewFacingForestOverloadGuard.Value) { _viewFacingForestThresholdState = "disabled"; _viewFacingForestRecoveryEligibleSince = -1f; TrySetViewFacingForestOverloadState(ViewFacingForestOverloadState.Normal); return; } int num = Mathf.Max(1, (_visibleDetailedTriangleSoftLimit != null) ? _visibleDetailedTriangleSoftLimit.Value : 220000); int num2 = Mathf.Max(num + 1, (_visibleDetailedTriangleHardLimit != null) ? _visibleDetailedTriangleHardLimit.Value : 320000); int num3 = Mathf.Max(1, (_visibleTreeRendererSoftLimit != null) ? _visibleTreeRendererSoftLimit.Value : 450); int num4 = Mathf.Max(num3 + 1, (_visibleTreeRendererHardLimit != null) ? _visibleTreeRendererHardLimit.Value : 650); bool flag = _visibleDetailedTriangles >= num2 || _visibleDetailedTreeRenderers >= num4; bool flag2 = _visibleDetailedTriangles >= num || _visibleDetailedTreeRenderers >= num3; _viewFacingForestThresholdState = (flag ? "hard exceeded" : (flag2 ? "soft exceeded" : "below soft")); if (flag) { _viewFacingForestRecoveryEligibleSince = -1f; TrySetViewFacingForestOverloadState(ViewFacingForestOverloadState.Hard); } else if (_viewFacingForestOverloadState == ViewFacingForestOverloadState.Hard) { if (!((float)_visibleDetailedTriangles <= (float)num2 * 0.85f) || !((float)_visibleDetailedTreeRenderers <= (float)num4 * 0.85f)) { _viewFacingForestRecoveryEligibleSince = -1f; return; } if (_viewFacingForestRecoveryEligibleSince < 0f) { _viewFacingForestRecoveryEligibleSince = now; } if (now - _viewFacingForestRecoveryEligibleSince >= 2.5f) { TrySetViewFacingForestOverloadState(flag2 ? ViewFacingForestOverloadState.Soft : ViewFacingForestOverloadState.Normal); _viewFacingForestRecoveryEligibleSince = -1f; } } else if (_viewFacingForestOverloadState == ViewFacingForestOverloadState.Soft) { if (!((float)_visibleDetailedTriangles <= (float)num * 0.8f) || !((float)_visibleDetailedTreeRenderers <= (float)num3 * 0.8f)) { _viewFacingForestRecoveryEligibleSince = -1f; return; } if (_viewFacingForestRecoveryEligibleSince < 0f) { _viewFacingForestRecoveryEligibleSince = now; } if (now - _viewFacingForestRecoveryEligibleSince >= 2.5f) { TrySetViewFacingForestOverloadState(ViewFacingForestOverloadState.Normal); _viewFacingForestRecoveryEligibleSince = -1f; } } else { _viewFacingForestRecoveryEligibleSince = -1f; if (flag2) { TrySetViewFacingForestOverloadState(ViewFacingForestOverloadState.Soft); } } } private void TrySetViewFacingForestOverloadState(ViewFacingForestOverloadState next) { if (_viewFacingForestOverloadState != next) { string a = PerformanceSafetyContentFingerprint(); ViewFacingForestOverloadState viewFacingForestOverloadState = _viewFacingForestOverloadState; _viewFacingForestOverloadState = next; string b = PerformanceSafetyContentFingerprint(); if (!string.Equals(a, b, StringComparison.Ordinal)) { _viewFacingForestOverloadState = viewFacingForestOverloadState; _viewFacingForestOverloadGuardSafetyValid = false; ((BaseUnityPlugin)this).Logger.LogError((object)"VIEW-FACING OVERLOAD GUARD SAFETY ASSERTION FAILED; guard disabled without changing forest content."); return; } _viewFacingForestOverloadTransitions++; _treeRendererPropertiesDirty = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("View-facing forest overload guard " + viewFacingForestOverloadState.ToString() + " -> " + next.ToString() + "; logical cards and accepted positions preserved.")); } } private string PerformanceSafetyContentFingerprint() { long num = 0L; long num2 = 0L; long num3 = 0L; int num4 = 0; foreach (ForestTile value in _forestTiles.Values) { if (value == null) { continue; } num += value.TreeCardCount; int[] stableCardRecords = value.StableCardRecords; if (stableCardRecords != null) { for (int i = 0; i < stableCardRecords.Length; i++) { num2++; num3 += (uint)stableCardRecords[i]; num4 ^= stableCardRecords[i]; } } } return CurrentForestGenerationSignatureBase() + "|safetyE=" + ExtensionDistance().ToString("R", CultureInfo.InvariantCulture) + "|safetyOuter=" + FinalForestRange().ToString("R", CultureInfo.InvariantCulture) + "|densityPreset=" + ((_treeCardDensityPreset != null) ? _treeCardDensityPreset.Value.ToString() : "unbound") + "|accepted=" + _densityAcceptedCards + "," + _baselinePrimaryCardsAccepted + "," + _reinforcementCardsAccepted + "," + _blackForestDensityCardsAccepted + "," + _meadowsDensityCardsAccepted + "," + _swampDensityCardsAccepted + "," + _mountainDensityCardsAccepted + "," + _plainsDensityCardsAccepted + "|activeLogical=" + num + "|stable=" + num2 + "," + num3 + "," + num4 + "|pineTargets=" + BlackForestTallPineTarget(ForestRing.Handoff).ToString("R", CultureInfo.InvariantCulture) + "," + BlackForestTallPineTarget(ForestRing.Near).ToString("R", CultureInfo.InvariantCulture) + "," + BlackForestTallPineTarget(ForestRing.Mid).ToString("R", CultureInfo.InvariantCulture) + "," + BlackForestTallPineTarget(ForestRing.Far).ToString("R", CultureInfo.InvariantCulture) + "," + BlackForestTallPineTarget(ForestRing.Horizon).ToString("R", CultureInfo.InvariantCulture); } private void HideAllTiles() { foreach (TerrainTile value in _terrainTiles.Values) { if ((Object)(object)value.Renderer != (Object)null) { ((Renderer)value.Renderer).enabled = false; } } foreach (ForestTile value2 in _forestTiles.Values) { value2.SetEnabled(enabled: false); } } private void ClearAllTiles(bool immediateForestDestroy = false) { ClearTerrainTilesOnly(); InvalidateAllForestTiles("full reload/provider change", immediateForestDestroy); } private void OnDestroy() { RestoreHazeIfNeeded(); RestoreTrueColourTargetDiagnostics(); RestoreCameraFarClipIfNeeded(); ClearAllTiles(immediateForestDestroy: true); DestroyMaterials(); DisposeProvider(); DestroyAllCalibrationVisuals(); if ((Object)(object)_calibrationGuideMaterial != (Object)null) { Object.Destroy((Object)(object)_calibrationGuideMaterial); } if ((Object)(object)_calibrationMarkerMaterial != (Object)null) { Object.Destroy((Object)(object)_calibrationMarkerMaterial); } if ((Object)(object)_calibrationFacingMarkerMaterial != (Object)null) { Object.Destroy((Object)(object)_calibrationFacingMarkerMaterial); } if ((Object)(object)_calibrationTestGuideMaterial != (Object)null) { Object.Destroy((Object)(object)_calibrationTestGuideMaterial); } if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)_root); } } private void DisposeProvider() { if (_provider != null) { _provider.Dispose(); _provider = null; } } private void DestroyMaterials() { if ((Object)(object)_sharedTerrainMaterial != (Object)null) { Object.Destroy((Object)(object)_sharedTerrainMaterial); } if ((Object)(object)_forestMaterial != (Object)null) { Object.Destroy((Object)(object)_forestMaterial); } if ((Object)(object)_treeCardMaterial != (Object)null) { Object.Destroy((Object)(object)_treeCardMaterial); } if ((Object)(object)_canopyCardMaterial != (Object)null) { Object.Destroy((Object)(object)_canopyCardMaterial); } if ((Object)(object)_mountainBiomeCardMaterial != (Object)null) { Object.Destroy((Object)(object)_mountainBiomeCardMaterial); } if ((Object)(object)_swampBiomeCardMaterial != (Object)null) { Object.Destroy((Object)(object)_swampBiomeCardMaterial); } if ((Object)(object)_treeAtlasTexture != (Object)null) { Object.Destroy((Object)(object)_treeAtlasTexture); } if ((Object)(object)_canopyAtlasTexture != (Object)null) { Object.Destroy((Object)(object)_canopyAtlasTexture); } if ((Object)(object)_mountainBiomeAtlasTexture != (Object)null) { Object.Destroy((Object)(object)_mountainBiomeAtlasTexture); } if ((Object)(object)_swampBiomeAtlasTexture != (Object)null) { Object.Destroy((Object)(object)_swampBiomeAtlasTexture); } _sharedTerrainMaterial = null; _forestMaterial = null; _treeCardMaterial = null; _canopyCardMaterial = null; _mountainBiomeCardMaterial = null; _swampBiomeCardMaterial = null; _treeAtlasTexture = null; _canopyAtlasTexture = null; _mountainBiomeAtlasTexture = null; _swampBiomeAtlasTexture = null; _treeCardCutoutMaterialValid = false; _treeCardCutoutMaterialValidLogged = false; _treeCardCutoutMaterialDetail = "not created"; _forestAtlasTextureWaitLogged = false; _forestAtlasMaterialsReadyLogged = false; _treeRendererPropertyStates.Clear(); _treeRendererPropertiesDirty = true; } private void EnsureRoot() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if ((Object)(object)_root == (Object)null) { _root = new GameObject("DonegalHorizonLiftRoot"); Object.DontDestroyOnLoad((Object)(object)_root); } } private Camera GetWorldCamera() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 if ((Object)(object)Camera.main != (Object)null) { return Camera.main; } Camera[] allCameras = Camera.allCameras; foreach (Camera val in allCameras) { if ((Object)(object)val != (Object)null && ((Behaviour)val).isActiveAndEnabled && (int)val.cameraType == 1) { return val; } } if (allCameras.Length == 0) { return null; } return allCameras[0]; } private void ApplyCameraFarClip(Camera camera) { if (!_extendMainCameraFarClip.Value || (Object)(object)camera == (Object)null) { RestoreCameraFarClipIfNeeded(); return; } float num = CameraFarClip(); if (!(camera.farClipPlane >= num)) { if (!_farClipApplied || (Object)(object)_farClipCamera != (Object)(object)camera) { RestoreCameraFarClipIfNeeded(); _farClipCamera = camera; _savedFarClip = camera.farClipPlane; _farClipApplied = true; } camera.farClipPlane = num; } } private void RestoreCameraFarClipIfNeeded() { if (_farClipApplied) { if ((Object)(object)_farClipCamera != (Object)null && _farClipCamera.farClipPlane > _savedFarClip) { _farClipCamera.farClipPlane = _savedFarClip; } _farClipCamera = null; _savedFarClip = 0f; _farClipApplied = false; } } private static Vector3 GetReferencePosition(Camera camera) { //IL_0017: 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_0026: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer != (Object)null) { return ((Component)Player.m_localPlayer).transform.position; } if (!((Object)(object)camera != (Object)null)) { return Vector3.zero; } return ((Component)camera).transform.position; } private void RefreshNativeEnvelope() { float value = _manualNearWorldExclusionRadius.Value; if (value > 0f) { _nativeEnvelopeRadius = Mathf.Max(_minimumNearWorldExclusionRadius.Value, value); _renderLimitsUsable = true; _nativeEnvelopeDetails = "manual exclusion radius " + _nativeEnvelopeRadius.ToString("F0", CultureInfo.InvariantCulture) + "m"; return; } _renderLimitsUsable = false; string text = "missing"; if (Chainloader.PluginInfos != null && Chainloader.PluginInfos.ContainsKey("render_limits")) { PluginInfo val = Chainloader.PluginInfos["render_limits"]; text = "detected " + ((val != null && val.Metadata != null) ? val.Metadata.Version.ToString() : "unknown version"); } string text2 = ResolvePath(_renderLimitsConfigFile.Value, Paths.ConfigPath); if (!File.Exists(text2)) { _nativeEnvelopeRadius = Mathf.Max(_minimumNearWorldExclusionRadius.Value, 900f); _renderLimitsStatus = "Render Limits " + text + "; config missing at " + text2; _nativeEnvelopeDetails = _renderLimitsStatus + ". Custom geometry disabled unless manual radius is explicitly allowed."; return; } Dictionary values = ReadSimpleConfig(text2); float configFloat = GetConfigFloat(values, "Generated zones", 0f); float configFloat2 = GetConfigFloat(values, "Loaded zones", 0f); float configFloat3 = GetConfigFloat(values, "Real terrain visibility", 0f); float num = Mathf.Max(configFloat, configFloat2) * 64f + 64f; float num2 = Mathf.Max(num, configFloat3) + _nativeEnvelopePadding.Value; _nativeEnvelopeRadius = Mathf.Max(_minimumNearWorldExclusionRadius.Value, num2); _renderLimitsUsable = Chainloader.PluginInfos != null && Chainloader.PluginInfos.ContainsKey("render_limits"); _renderLimitsStatus = "Render Limits " + text + "; config " + text2; _nativeEnvelopeDetails = "generatedZones=" + configFloat.ToString("F0", CultureInfo.InvariantCulture) + ", loadedZones=" + configFloat2.ToString("F0", CultureInfo.InvariantCulture) + ", realTerrain=" + configFloat3.ToString("F0", CultureInfo.InvariantCulture) + "m, padding=" + _nativeEnvelopePadding.Value.ToString("F0", CultureInfo.InvariantCulture) + "m => exclusion=" + _nativeEnvelopeRadius.ToString("F0", CultureInfo.InvariantCulture) + "m"; } private void RefreshNativeTreeViewDistance() { float num = (_nativeTreeViewDistance = Mathf.Max(1f, (_nativeTreeViewDistanceFallback != null) ? _nativeTreeViewDistanceFallback.Value : 215f)); _nativeTreeRangeSource = "fallback " + num.ToString("F0", CultureInfo.InvariantCulture) + "m"; if (_autoDetectNativeTreeViewDistance == null || !_autoDetectNativeTreeViewDistance.Value) { _nativeTreeRangeSource = "auto disabled; fallback " + num.ToString("F0", CultureInfo.InvariantCulture) + "m"; return; } try { string path = ResolvePath(_renderLimitsConfigFile.Value, Paths.ConfigPath); if (!File.Exists(path)) { _nativeTreeRangeSource = "Render Limits config missing; fallback " + num.ToString("F0", CultureInfo.InvariantCulture) + "m"; return; } Dictionary values = ReadSimpleConfig(path); if (TryGetFirstConfigFloat(values, out var parsed, out var key, "Tree View Distance", "Tree View Distance In Metres", "Tree visibility", "Tree Visibility") && parsed > 0f) { _nativeTreeViewDistance = parsed; _nativeTreeRangeSource = "Render Limits " + key; } else { _nativeTreeRangeSource = "no dedicated tree/vegetation range key found; fallback " + num.ToString("F0", CultureInfo.InvariantCulture) + "m"; } } catch (Exception ex) { _nativeTreeRangeSource = "detection failed: " + ex.Message + "; fallback " + num.ToString("F0", CultureInfo.InvariantCulture) + "m"; } } private void ScanDuplicateDlls() { try { string[] array = (Directory.Exists(Paths.PluginPath) ? Directory.GetFiles(Paths.PluginPath, "DonegalHorizonLift.dll", SearchOption.AllDirectories) : new string[0]); _duplicateDllStatus = array.Length + " DonegalHorizonLift.dll file(s) under plugins."; for (int i = 0; i < array.Length; i++) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Donegal Horizon Lift DLL found: " + array[i])); } if (array.Length > 1) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Duplicate DonegalHorizonLift.dll files detected. Move old backups/source/bin/obj folders outside BepInEx/plugins before testing."); } } catch (Exception ex) { _duplicateDllStatus = "duplicate scan failed: " + ex.Message; ((BaseUnityPlugin)this).Logger.LogWarning((object)_duplicateDllStatus); } } private void ReportIgnoredLegacySettings() { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Exact biome-density table active; ignored legacy density values: " + LegacyBiomeDensitySettingsSummary())); try { string path = Path.Combine(Paths.ConfigPath, "marc.donegalhorizonlift.cfg"); if (!File.Exists(path)) { _legacyConfigStatus = "no existing config to scan"; return; } string text = File.ReadAllText(path); string[] array = new string[13] { "Terrain Support Underlay", "SupportTileJob", "Support Start", "Support Skirt", "One Support Tile", "Vanilla Tree Handoff", "Hide Beyond", "ProceduralWorld", "Procedural Mode Experimental", "Procedural Cache", "Sprites/Default", "Ridge Forest", "Skyline Forest" }; int num = 0; for (int i = 0; i < array.Length; i++) { if (text.IndexOf(array[i], StringComparison.OrdinalIgnoreCase) >= 0) { num++; ((BaseUnityPlugin)this).Logger.LogWarning((object)("Legacy setting detected and ignored by Recovery Release: " + array[i])); } } _legacyConfigStatus = ((num == 0) ? "no risky legacy settings detected" : (num + " risky legacy setting name(s) detected and ignored")); } catch (Exception ex) { _legacyConfigStatus = "legacy config scan failed: " + ex.Message; ((BaseUnityPlugin)this).Logger.LogWarning((object)_legacyConfigStatus); } } private static string GetPluginDirectory() { string location = Assembly.GetExecutingAssembly().Location; if (!string.IsNullOrEmpty(location)) { string directoryName = Path.GetDirectoryName(location); if (!string.IsNullOrEmpty(directoryName)) { return directoryName; } } return Paths.PluginPath; } private void UpdateHazeState() { _weatherName = ResolveCurrentEnvironmentName(); _weatherClassification = ClassifyWeather(_weatherName); _externalFogStatus = GetExternalFogStatus(); _hazeYieldReason = "none"; if (_hazeControlMode.Value == HazeControlMode.Disabled) { RestoreHazeIfNeeded(); _hazeStatus = "disabled in config"; return; } if (!RenderSettings.fog) { RestoreHazeIfNeeded(); _hazeStatus = "RenderSettings fog is off"; return; } if (ShouldYieldToExternalFog(out _hazeYieldReason)) { RestoreHazeIfNeeded(); _hazeStatus = "yielding to external fog control: " + _hazeYieldReason; return; } if ((_preserveBossWeather == null || _preserveBossWeather.Value) && IsBossWeatherName(_weatherName)) { RestoreHazeIfNeeded(); _hazeStatus = "boss weather preserved: " + _weatherName; return; } if (!IsClearWeatherHazeEligible(_weatherName, _weatherClassification, out _hazeYieldReason)) { RestoreHazeIfNeeded(); _hazeStatus = _hazeYieldReason; return; } string text = _weatherName + "|" + _weatherClassification; bool flag = !string.Equals(text, _lastHazeEnvironmentKey, StringComparison.Ordinal); bool flag2 = !_hazeApplied || Mathf.Abs(RenderSettings.fogDensity - _appliedFogDensity) > 5E-05f; if (!_hazeApplied || flag || flag2) { _savedFogDensity = RenderSettings.fogDensity; _savedFogEnabled = RenderSettings.fog; _lastHazeEnvironmentKey = text; _hazeApplied = true; } if (_enableRealClearSkies != null && _enableRealClearSkies.Value) { ApplyRealClearSkies(); return; } float num = ((_weatherClassification == "light") ? _lightCloudHazeMultiplier.Value : _clearWeatherHazeMultiplier.Value); float num2 = 1f - Mathf.Clamp01(_maximumHazeReduction.Value); float num3 = Mathf.Clamp(num, num2, 1f); _targetFogDensity = _savedFogDensity * num3; if (_savedFogDensity <= 0.0001f) { _appliedFogDensity = RenderSettings.fogDensity; _hazeStatus = "active " + _weatherClassification + " weather, but current fog density is zero; no visible haze change"; return; } float num4 = Time.deltaTime * Mathf.Max(0.25f, _hazeBlendSpeed.Value) * Mathf.Max(0.0001f, _savedFogDensity); RenderSettings.fogDensity = Mathf.MoveTowards(RenderSettings.fogDensity, _targetFogDensity, num4); _appliedFogDensity = RenderSettings.fogDensity; _hazeStatus = "active " + _weatherClassification + " weather multiplier " + num3.ToString("F2", CultureInfo.InvariantCulture); } private void ApplyRealClearSkies() { try { string reason; string biomeName; ClearSkyWeatherTier clearSkyWeatherTier = (_clearSkyTier = ClassifyClearSkyTier(out reason, out biomeName)); _clearSkyPreservationReason = reason; _clearSkyBiomeName = biomeName; float num = ((_clearSkiesStrength != null) ? Mathf.Clamp01(_clearSkiesStrength.Value) : 0.85f); ClearSkiesOperatingMode clearSkiesOperatingMode = ((_clearSkiesOperatingMode != null) ? _clearSkiesOperatingMode.Value : ClearSkiesOperatingMode.NaturalWeatherAndOccasionalEvent); bool flag = UpdateCrystalClearEventState(clearSkiesOperatingMode, clearSkyWeatherTier); float num2 = ((clearSkiesOperatingMode == ClearSkiesOperatingMode.Disabled) ? 0f : (clearSkyWeatherTier switch { ClearSkyWeatherTier.Clear => num, ClearSkyWeatherTier.PartlyClear => num * 0.5f, _ => 0f, })); if (!Mathf.Approximately(num2, _clearSkyTargetBlend)) { _lastClearSkyEnvironmentChangeRealtime = Time.realtimeSinceStartup; } _clearSkyTargetBlend = num2; float num3 = Mathf.Max(0.1f, (_clearSkiesTransitionSeconds != null) ? _clearSkiesTransitionSeconds.Value : 10f); float num4 = Time.unscaledDeltaTime / num3; _clearSkyCurrentBlend = Mathf.MoveTowards(_clearSkyCurrentBlend, _clearSkyTargetBlend, num4); float num5 = ((!flag) ? ((_clearWeatherFogMultiplier != null) ? _clearWeatherFogMultiplier.Value : 0.2f) : ((_crystalClearFogMultiplier != null) ? _crystalClearFogMultiplier.Value : 0.08f)); float num6 = ((!flag) ? ((_clearWeatherHorizonHazeMultiplier != null) ? _clearWeatherHorizonHazeMultiplier.Value : 0.25f) : ((_crystalClearHorizonHazeMultiplier != null) ? _crystalClearHorizonHazeMultiplier.Value : 0.08f)); float num7 = ((!flag) ? ((_clearWeatherDistanceTintMultiplier != null) ? _clearWeatherDistanceTintMultiplier.Value : 0.7f) : ((_crystalClearDistanceTintMultiplier != null) ? _crystalClearDistanceTintMultiplier.Value : 0.45f)); float num8 = (_clearSkyAppliedFogMultiplier = Mathf.Lerp(1f, num5, _clearSkyCurrentBlend)); _targetFogDensity = _savedFogDensity * num8; RenderSettings.fogDensity = _targetFogDensity; _appliedFogDensity = RenderSettings.fogDensity; _clearSkyAppliedHazeMultiplier = Mathf.Lerp(1f, num6, _clearSkyCurrentBlend); _clearSkyAppliedTintMultiplier = Mathf.Lerp(1f, num7, _clearSkyCurrentBlend); ApplyClearSkyCloudControl(_clearSkyCurrentBlend, flag); _hazeStatus = "Real Clear Skies: " + clearSkiesOperatingMode.ToString() + " | " + clearSkyWeatherTier.ToString() + (flag ? " | CRYSTAL CLEAR EVENT ACTIVE" : "") + " blend " + _clearSkyCurrentBlend.ToString("F2", CultureInfo.InvariantCulture) + "/" + _clearSkyTargetBlend.ToString("F2", CultureInfo.InvariantCulture) + " (" + reason + ")"; _lastClearSkyException = "none"; } catch (Exception ex) { _lastClearSkyException = ex.GetType().Name + ": " + ex.Message; ((BaseUnityPlugin)this).Logger.LogWarning((object)("[New Horizons Treelines] Real Clear Skies update failed: " + _lastClearSkyException)); } } private bool UpdateCrystalClearEventState(ClearSkiesOperatingMode mode, ClearSkyWeatherTier tier) { if (mode != ClearSkiesOperatingMode.NaturalWeatherAndOccasionalEvent || (_allowOccasionalCrystalClearWeather != null && !_allowOccasionalCrystalClearWeather.Value) || tier != ClearSkyWeatherTier.Clear) { _crystalClearEventActive = false; _crystalClearEventRemainingSecondsForDiagnostics = 0f; return false; } if (_crystalClearEventActive) { float num = _crystalClearEventEndRealtime - Time.realtimeSinceStartup; if (num <= 0f) { _crystalClearEventActive = false; _crystalClearEventRemainingSecondsForDiagnostics = 0f; } else { _crystalClearEventRemainingSecondsForDiagnostics = num; } return _crystalClearEventActive; } int num2 = CurrentValheimDayNumber(); if (num2 != _crystalClearScheduledForDay) { _crystalClearScheduledForDay = num2; int a = ((_provider != null) ? _provider.StableSeed : 0); float num3 = Hash01(HashCombine(a, num2, 90210)); float num4 = ((_crystalClearChancePerClearDay != null) ? Mathf.Clamp01(_crystalClearChancePerClearDay.Value) : 0.2f); if (num3 < num4) { float num5 = ((_crystalClearMinimumDurationMinutes != null) ? _crystalClearMinimumDurationMinutes.Value : 4f); float num6 = ((_crystalClearMaximumDurationMinutes != null) ? _crystalClearMaximumDurationMinutes.Value : 12f); float num7 = Mathf.Lerp(num5, Mathf.Max(num5, num6), Hash01(HashCombine(a, num2, 55443))); _crystalClearEventActive = true; _crystalClearEventEndRealtime = Time.realtimeSinceStartup + num7 * 60f; _crystalClearEventRemainingSecondsForDiagnostics = num7 * 60f; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[New Horizons Treelines] Crystal Clear event started (day " + num2 + ", " + num7.ToString("F1", CultureInfo.InvariantCulture) + " min)")); } } return _crystalClearEventActive; } private int CurrentValheimDayNumber() { try { if ((Object)(object)ZNet.instance != (Object)null && (Object)(object)EnvMan.instance != (Object)null && EnvMan.instance.m_dayLengthSec > 0) { return Mathf.FloorToInt((float)(ZNet.instance.GetTimeSeconds() / (double)EnvMan.instance.m_dayLengthSec)); } } catch (Exception) { } return Mathf.FloorToInt(Time.realtimeSinceStartup / 1800f); } private ClearSkyWeatherTier ClassifyClearSkyTier(out string reason, out string biomeName) { biomeName = TryGetPlayerBiomeName(); if (!string.IsNullOrEmpty(biomeName)) { string text = biomeName.ToLowerInvariant(); if (text.Contains("mistlands") && (_preserveMistlandsMist == null || _preserveMistlandsMist.Value)) { reason = "Mistlands atmosphere preserved"; return ClearSkyWeatherTier.SpecialBiome; } if (text.Contains("ashlands") && (_preserveAshlandsAtmosphere == null || _preserveAshlandsAtmosphere.Value)) { reason = "Ashlands atmosphere preserved"; return ClearSkyWeatherTier.SpecialBiome; } if (text.Contains("deepnorth") && (_preserveDeepNorthAtmosphere == null || _preserveDeepNorthAtmosphere.Value)) { reason = "Deep North atmosphere preserved"; return ClearSkyWeatherTier.SpecialBiome; } } if ((_preserveBossWeather == null || _preserveBossWeather.Value) && IsBossWeatherName(_weatherName)) { reason = "boss weather preserved: " + _weatherName; return ClearSkyWeatherTier.Bad; } bool value; if (_weatherClassification == "blocked") { string text2 = (_weatherName ?? "").ToLowerInvariant(); if (!text2.Contains("rain") && !text2.Contains("snow") && !text2.Contains("blizzard")) { if (_preserveStormWeather != null) { value = _preserveStormWeather.Value; goto IL_0157; } } else if (_preserveRainAndSnow != null) { value = _preserveRainAndSnow.Value; goto IL_0157; } goto IL_015b; } if (_weatherClassification == "light") { reason = "partly clear: " + _weatherName; return ClearSkyWeatherTier.PartlyClear; } if (_weatherClassification == "clear") { reason = "clear: " + _weatherName; return ClearSkyWeatherTier.Clear; } reason = "unknown/unclassified weather, treated as bad (fail closed): " + _weatherName; return ClearSkyWeatherTier.Bad; IL_015b: reason = "bad weather preserved: " + _weatherName; return ClearSkyWeatherTier.Bad; IL_0157: if (!value) { reason = "bad weather (preservation disabled by config): " + _weatherName; return ClearSkyWeatherTier.PartlyClear; } goto IL_015b; } private static bool IsBossWeatherName(string environmentName) { string text = (environmentName ?? "").ToLowerInvariant(); if (!text.Contains("boss") && !text.Contains("eikthyr") && !text.Contains("gdking") && !text.Contains("bonemass") && !text.Contains("moder") && !text.Contains("goblinking") && !text.Contains("queen")) { return text.Contains("fader"); } return true; } private string TryGetPlayerBiomeName() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!_playerBiomeApiChecked) { _playerBiomeApiChecked = true; _playerBiomeApiAvailable = true; } if (!_playerBiomeApiAvailable) { return ""; } try { if ((Object)(object)Player.m_localPlayer == (Object)null) { return ""; } return ((object)Player.m_localPlayer.GetCurrentBiome()/*cast due to .constrained prefix*/).ToString(); } catch (Exception) { _playerBiomeApiAvailable = false; return ""; } } private void EnsureCloudRenderersScanned() { //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) if (_cloudRenderersScanned) { return; } _cloudRenderersScanned = true; _cloudRenderers.Clear(); _cloudRendererOriginalColours.Clear(); _cloudRendererOriginalBlocks.Clear(); try { Renderer[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Renderer val in array) { if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || (Object)(object)val.sharedMaterial == (Object)null) { continue; } string text = ((Object)((Component)val).gameObject).name.ToLowerInvariant(); if (text.Contains("cloud") && val.sharedMaterial.HasProperty("_Color")) { if (_cloudRenderers.Count == 0) { _cloudOriginalAlphaForDiagnostics = val.sharedMaterial.color.a; } _cloudRenderers.Add(val); _cloudRendererOriginalColours[val] = val.sharedMaterial.color; MaterialPropertyBlock val2 = new MaterialPropertyBlock(); val.GetPropertyBlock(val2); _cloudRendererOriginalBlocks[val] = val2; } } _cloudControlStatus = ((_cloudRenderers.Count > 0) ? ("found " + _cloudRenderers.Count + " candidate cloud renderer(s) by name scan") : "no compatible cloud renderer found by name scan -- cloud opacity control not available this session (fog/haze/tint controls are unaffected)"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[New Horizons Treelines] Real Clear Skies cloud scan: " + _cloudControlStatus)); } catch (Exception ex) { _cloudControlStatus = "cloud renderer scan failed: " + ex.Message; } } private void ApplyClearSkyCloudControl(float amount, bool inCrystalClearEvent) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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) EnsureCloudRenderersScanned(); if (_cloudRenderers.Count == 0) { return; } if (_cloudPropertyBlock == null) { _cloudPropertyBlock = new MaterialPropertyBlock(); } float num = ((!inCrystalClearEvent) ? ((_clearWeatherCloudOpacityMultiplier != null) ? _clearWeatherCloudOpacityMultiplier.Value : 0.45f) : ((_crystalClearCloudOpacityMultiplier != null) ? _crystalClearCloudOpacityMultiplier.Value : 0.15f)); float num2 = (_cloudAppliedOpacityMultiplier = Mathf.Lerp(1f, num, amount)); for (int i = 0; i < _cloudRenderers.Count; i++) { Renderer val = _cloudRenderers[i]; if (!((Object)(object)val == (Object)null) && _cloudRendererOriginalColours.TryGetValue(val, out var value)) { Color val2 = value; val2.a = value.a * num2; if (_cloudRendererOriginalBlocks.TryGetValue(val, out var value2)) { val.SetPropertyBlock(value2); } val.GetPropertyBlock(_cloudPropertyBlock); _cloudPropertyBlock.SetColor("_Color", val2); val.SetPropertyBlock(_cloudPropertyBlock); } } } private void RestoreCloudRenderersIfNeeded() { if (!_cloudRenderersScanned) { return; } _cloudRestoreOk = true; for (int i = 0; i < _cloudRenderers.Count; i++) { Renderer val = _cloudRenderers[i]; if (!((Object)(object)val == (Object)null)) { if (_cloudRendererOriginalBlocks.TryGetValue(val, out var value)) { val.SetPropertyBlock(value); } else { _cloudRestoreOk = false; } } } _cloudAppliedOpacityMultiplier = 1f; } private void UpdateTrueColourTargetDiagnostics() { //IL_009a: 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_0089: 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_0076: Unknown result type (might be due to invalid IL or missing references) TrueColourDiagnosticTarget trueColourDiagnosticTarget = ((_trueColourDiagnosticTarget != null) ? _trueColourDiagnosticTarget.Value : TrueColourDiagnosticTarget.Off); if (trueColourDiagnosticTarget != _lastTrueColourDiagnosticTarget) { RestoreTrueColourTargetDiagnostics(); _lastTrueColourDiagnosticTarget = trueColourDiagnosticTarget; } if (trueColourDiagnosticTarget == TrueColourDiagnosticTarget.NativeFogOutput) { Color val = default(Color); ((Color)(ref val))..ctor(0f, 1f, 0.1f, 1f); if (_fogColourDiagnosticApplied && !ApproximatelyColour(RenderSettings.fogColor, val)) { _fogColourDiagnosticOverwritten = true; } if (!_fogColourDiagnosticApplied) { _savedFogColour = RenderSettings.fogColor; _fogColourDiagnosticOverwritten = false; _fogColourDiagnosticApplied = true; } RenderSettings.fogColor = val; } else if (_fogColourDiagnosticApplied) { RenderSettings.fogColor = _savedFogColour; _fogColourDiagnosticApplied = false; } if (trueColourDiagnosticTarget == TrueColourDiagnosticTarget.NativeTerrainMaterial) { ApplyNativeTerrainDiagnostic(); } else { RestoreNativeTerrainDiagnostic(); } } private void ApplyNativeTerrainDiagnostic() { //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Expected O, but got Unknown //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown if (!_nativeTerrainDiagnosticApplied) { _nativeTerrainDiagnosticOriginalBlocks.Clear(); Heightmap[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] == (Object)null) { continue; } Renderer[] componentsInChildren = ((Component)array[i]).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { Material val2 = (((Object)(object)val != (Object)null) ? val.sharedMaterial : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null)) { string text = (((Object)val2).name + "|" + (((Object)(object)val2.shader != (Object)null) ? ((Object)val2.shader).name : "")).ToLowerInvariant(); if (text.Contains("terrain") || text.Contains("heightmap") || text.Contains("ground")) { MaterialPropertyBlock val3 = new MaterialPropertyBlock(); val.GetPropertyBlock(val3); _nativeTerrainDiagnosticOriginalBlocks[val] = val3; } } } } _nativeTerrainDiagnosticApplied = _nativeTerrainDiagnosticOriginalBlocks.Count > 0; _nativeTerrainDiagnosticStatus = (_nativeTerrainDiagnosticApplied ? ("target found: " + _nativeTerrainDiagnosticOriginalBlocks.Count + " native terrain renderer(s)") : "target not found: no live Heightmap terrain renderer/material matched"); } foreach (KeyValuePair nativeTerrainDiagnosticOriginalBlock in _nativeTerrainDiagnosticOriginalBlocks) { Renderer key = nativeTerrainDiagnosticOriginalBlock.Key; if (!((Object)(object)key == (Object)null)) { MaterialPropertyBlock val4 = new MaterialPropertyBlock(); key.GetPropertyBlock(val4); val4.SetColor("_Color", new Color(1f, 0.1f, 0.85f, 1f)); key.SetPropertyBlock(val4); } } } private void RestoreNativeTerrainDiagnostic() { if (_nativeTerrainDiagnosticOriginalBlocks.Count > 0) { foreach (KeyValuePair nativeTerrainDiagnosticOriginalBlock in _nativeTerrainDiagnosticOriginalBlocks) { if ((Object)(object)nativeTerrainDiagnosticOriginalBlock.Key != (Object)null) { nativeTerrainDiagnosticOriginalBlock.Key.SetPropertyBlock(nativeTerrainDiagnosticOriginalBlock.Value); } } } _nativeTerrainDiagnosticOriginalBlocks.Clear(); _nativeTerrainDiagnosticApplied = false; if (_lastTrueColourDiagnosticTarget != TrueColourDiagnosticTarget.NativeTerrainMaterial) { _nativeTerrainDiagnosticStatus = "not selected"; } } private void RestoreTrueColourTargetDiagnostics() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (_fogColourDiagnosticApplied) { RenderSettings.fogColor = _savedFogColour; _fogColourDiagnosticApplied = false; } RestoreNativeTerrainDiagnostic(); } private static bool ApproximatelyColour(Color a, Color b) { //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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_004b: 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) if (Mathf.Abs(a.r - b.r) < 0.002f && Mathf.Abs(a.g - b.g) < 0.002f && Mathf.Abs(a.b - b.b) < 0.002f) { return Mathf.Abs(a.a - b.a) < 0.002f; } return false; } private void RestoreHazeIfNeeded() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (_fogColourDiagnosticApplied) { RenderSettings.fogColor = _savedFogColour; _fogColourDiagnosticApplied = false; } RestoreCloudRenderersIfNeeded(); _clearSkyCurrentBlend = 0f; _clearSkyTargetBlend = 0f; _clearSkyTier = ClearSkyWeatherTier.Bad; _clearSkyPreservationReason = "haze/clear-sky system inactive this tick"; if (!_hazeApplied) { _clearSkyRestoreOk = true; return; } RenderSettings.fogDensity = _savedFogDensity; RenderSettings.fog = _savedFogEnabled; _targetFogDensity = _savedFogDensity; _appliedFogDensity = RenderSettings.fogDensity; _clearSkyRestoreOk = Mathf.Abs(RenderSettings.fogDensity - _savedFogDensity) < 0.0005f && RenderSettings.fog == _savedFogEnabled; _hazeApplied = false; _lastHazeEnvironmentKey = ""; } private bool ShouldYieldToExternalFog(out string reason) { reason = "none"; if (_hazeControlMode.Value == HazeControlMode.ForceHorizonLiftFog) { return false; } if (_hazeControlMode.Value == HazeControlMode.YieldToExternal) { reason = "Haze Control Mode is YieldToExternal"; return true; } if (Chainloader.PluginInfos == null) { reason = "plugin list not ready"; return false; } if (Chainloader.PluginInfos.ContainsKey("vapok.mods.nofogbruh")) { string path = Path.Combine(Paths.ConfigPath, "vapok.mods.nofogbruh.cfg"); string a = ReadConfigValue(path, "Enable Fog Component"); if (string.Equals(a, "false", StringComparison.OrdinalIgnoreCase)) { _externalFogStatus = "No Fog Bruh detected; fog component disabled, AO-only compatible"; return false; } if (string.Equals(a, "true", StringComparison.OrdinalIgnoreCase)) { reason = "No Fog Bruh fog component is enabled"; _externalFogStatus = reason; return true; } reason = "No Fog Bruh detected, fog component setting unresolved"; _externalFogStatus = reason; return true; } foreach (KeyValuePair pluginInfo in Chainloader.PluginInfos) { string text = pluginInfo.Key ?? ""; string text2 = ((pluginInfo.Value != null && pluginInfo.Value.Metadata != null) ? pluginInfo.Value.Metadata.Name : ""); string text3 = (text + " " + text2).ToLowerInvariant(); if (!(text == "marc.donegalhorizonlift") && (text3.Contains("fog") || text3.Contains("mist"))) { reason = "possible external fog plugin: " + ((text2.Length > 0) ? text2 : text); _externalFogStatus = reason; return true; } } _externalFogStatus = "no active external fog controller detected"; return false; } private static string GetExternalFogStatus() { if (Chainloader.PluginInfos == null) { return "plugin list not ready"; } if (Chainloader.PluginInfos.ContainsKey("vapok.mods.nofogbruh")) { string a = ReadConfigValue(Path.Combine(Paths.ConfigPath, "vapok.mods.nofogbruh.cfg"), "Enable Fog Component"); if (string.Equals(a, "false", StringComparison.OrdinalIgnoreCase)) { return "No Fog Bruh present; fog component disabled, AO-only compatible"; } if (string.Equals(a, "true", StringComparison.OrdinalIgnoreCase)) { return "No Fog Bruh present; fog component enabled"; } return "No Fog Bruh present; fog component setting unresolved"; } return "no known external fog plugin"; } private static bool IsClearWeatherHazeEligible(string envName, string classification, out string reason) { reason = "not eligible"; try { if (classification == "blocked") { reason = "blocked heavy/weather environment: " + envName; return false; } if (classification == "unknown") { reason = "unknown/non-clear environment: " + envName; return false; } reason = "eligible " + classification + " environment: " + envName; return true; } catch (Exception ex) { reason = "eligibility check failed: " + ex.Message; return false; } } private string ResolveCurrentEnvironmentName() { try { if ((Object)(object)EnvMan.instance == (Object)null) { return "EnvMan missing"; } MethodInfo method = typeof(EnvMan).GetMethod("GetCurrentEnvironment", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method != null) { object value = method.Invoke(EnvMan.instance, null); string text = TryReadNamedString(value, 0); if (!string.IsNullOrEmpty(text)) { return text; } } string text2 = TryReadKnownMemberString(EnvMan.instance, 0); if (!string.IsNullOrEmpty(text2)) { return text2; } } catch (Exception ex) { return "weather read failed: " + ex.Message; } return "unknown"; } private static string ClassifyWeather(string envName) { string text = (envName ?? "").ToLowerInvariant(); if (text.Length == 0 || text == "unknown" || text.Contains("failed") || text.Contains("missing")) { return "unknown"; } if (text.Contains("mist") || text.Contains("rain") || text.Contains("storm") || text.Contains("snow") || text.Contains("swamp") || text.Contains("ash") || text.Contains("crypt") || text.Contains("eikthyr") || text.Contains("bonemass") || text.Contains("moder") || text.Contains("queen")) { return "blocked"; } if (text.Contains("cloud") || text.Contains("twilight") || text.Contains("heath") || text.Contains("morning") || text.Contains("evening")) { return "light"; } if (text.Contains("clear") || text.Contains("sun") || text.Contains("fair") || text.Contains("meadows") || text.Contains("mountainclear")) { return "clear"; } return "unknown"; } private static string TryReadNamedString(object value, int depth) { if (value == null || depth > 2) { return ""; } string text = value as string; if (!string.IsNullOrEmpty(text)) { return text; } string text2 = TryReadKnownMemberString(value, depth); if (!string.IsNullOrEmpty(text2)) { return text2; } string text3 = value.ToString(); if (!string.IsNullOrEmpty(text3) && text3 != value.GetType().FullName && text3 != value.GetType().Name) { return text3; } return ""; } private static string TryReadKnownMemberString(object value, int depth) { if (value == null || depth > 2) { return ""; } Type type = value.GetType(); string[] array = new string[9] { "m_name", "name", "Name", "m_env", "m_environment", "m_currentEnv", "m_currentEnvironment", "m_currentEnvName", "m_envName" }; BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; for (int i = 0; i < array.Length; i++) { try { FieldInfo field = type.GetField(array[i], bindingAttr); if (field != null) { string text = TryReadNamedString(field.GetValue(value), depth + 1); if (!string.IsNullOrEmpty(text)) { return text; } } PropertyInfo property = type.GetProperty(array[i], bindingAttr); if (property != null && property.GetIndexParameters().Length == 0) { string text2 = TryReadNamedString(property.GetValue(value, null), depth + 1); if (!string.IsNullOrEmpty(text2)) { return text2; } } } catch { } } return ""; } private void OnGUI() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_0498: Unknown result type (might be due to invalid IL or missing references) //IL_05f4: Unknown result type (might be due to invalid IL or missing references) //IL_06ea: Unknown result type (might be due to invalid IL or missing references) //IL_085c: Unknown result type (might be due to invalid IL or missing references) //IL_095f: Unknown result type (might be due to invalid IL or missing references) //IL_0a7a: Unknown result type (might be due to invalid IL or missing references) //IL_0b0c: Unknown result type (might be due to invalid IL or missing references) //IL_0b73: Unknown result type (might be due to invalid IL or missing references) //IL_0c06: Unknown result type (might be due to invalid IL or missing references) //IL_0c45: Unknown result type (might be due to invalid IL or missing references) //IL_0ced: Unknown result type (might be due to invalid IL or missing references) //IL_0dc7: Unknown result type (might be due to invalid IL or missing references) //IL_0e9b: Unknown result type (might be due to invalid IL or missing references) //IL_0ee8: Unknown result type (might be due to invalid IL or missing references) //IL_0f1c: Unknown result type (might be due to invalid IL or missing references) //IL_0f7e: Unknown result type (might be due to invalid IL or missing references) //IL_101e: Unknown result type (might be due to invalid IL or missing references) //IL_1101: Unknown result type (might be due to invalid IL or missing references) //IL_1140: Unknown result type (might be due to invalid IL or missing references) //IL_1169: Unknown result type (might be due to invalid IL or missing references) //IL_11f3: Unknown result type (might be due to invalid IL or missing references) //IL_1245: Unknown result type (might be due to invalid IL or missing references) //IL_12ed: Unknown result type (might be due to invalid IL or missing references) //IL_138c: Unknown result type (might be due to invalid IL or missing references) //IL_1476: Unknown result type (might be due to invalid IL or missing references) //IL_156a: Unknown result type (might be due to invalid IL or missing references) //IL_1687: Unknown result type (might be due to invalid IL or missing references) //IL_17bd: Unknown result type (might be due to invalid IL or missing references) //IL_18d0: Unknown result type (might be due to invalid IL or missing references) //IL_1a36: Unknown result type (might be due to invalid IL or missing references) //IL_1b14: Unknown result type (might be due to invalid IL or missing references) //IL_1b85: Unknown result type (might be due to invalid IL or missing references) //IL_1c24: Unknown result type (might be due to invalid IL or missing references) //IL_1cc3: Unknown result type (might be due to invalid IL or missing references) //IL_1d4a: Unknown result type (might be due to invalid IL or missing references) //IL_1e6d: Unknown result type (might be due to invalid IL or missing references) //IL_1f5d: Unknown result type (might be due to invalid IL or missing references) //IL_1fe4: Unknown result type (might be due to invalid IL or missing references) //IL_2055: Unknown result type (might be due to invalid IL or missing references) //IL_20b8: Unknown result type (might be due to invalid IL or missing references) //IL_219f: Unknown result type (might be due to invalid IL or missing references) //IL_2286: Unknown result type (might be due to invalid IL or missing references) //IL_22f7: Unknown result type (might be due to invalid IL or missing references) //IL_23f5: Unknown result type (might be due to invalid IL or missing references) //IL_24c4: Unknown result type (might be due to invalid IL or missing references) if (_overlayStyle == null) { _overlayStyle = new GUIStyle(GUI.skin.label); _overlayStyle.normal.textColor = Color.white; _overlayStyle.fontSize = 13; _overlayStyle.wordWrap = false; } if (_calibrationModeActive) { DrawCalibrationActivationBanner(); DrawCalibrationOverlay(); } else if (_calibrationGateWarningRemaining > 0f) { DrawCalibrationGateWarningBanner(); } if (!_showDebug.Value) { return; } if (Input.GetKeyDown((KeyCode)281)) { _debugPageIndex = (_debugPageIndex + 1) % 10; } if (Input.GetKeyDown((KeyCode)280)) { _debugPageIndex = (_debugPageIndex + 9) % 10; } if (_debugPageIndex == 1) { DrawTreelinePanel(); DrawSwampPanel(); DrawCalibrationDiagnosticsPanel(); return; } if (_debugPageIndex == 2) { DrawForestStreamingPanel(); return; } if (_debugPageIndex == 3) { DrawSwampGroundingPanel(); return; } if (_debugPageIndex == 4) { DrawRealClearSkiesPanel(); return; } if (_debugPageIndex == 5) { DrawStrictGroundingPanel(); return; } if (_debugPageIndex == 6) { DrawTrueColourDistantLandPanel(); return; } if (_debugPageIndex == 7) { DrawTreeLightingPanel(); return; } if (_debugPageIndex == 8) { DrawHandoffFillPanel(); return; } if (_debugPageIndex == 9) { DrawHorizonCoveragePanel(); return; } Camera worldCamera = GetWorldCamera(); object obj; if (!((Object)(object)worldCamera != (Object)null)) { obj = "missing"; } else { string[] obj2 = new string[5] { ((Object)worldCamera).name, " pos ", null, null, null }; Vector3 position = ((Component)worldCamera).transform.position; obj2[2] = ((Vector3)(ref position)).ToString("F0"); obj2[3] = " far "; obj2[4] = Mathf.RoundToInt(worldCamera.farClipPlane).ToString(); obj = string.Concat(obj2); } string text = (string)obj; string text2 = ((_nearestForestTileDistance < float.MaxValue) ? (((Vector3)(ref _nearestForestTileCenter)).ToString("F0") + " / " + Mathf.RoundToInt(_nearestForestTileDistance) + "m / density " + _nearestForestDensity.ToString("F2")) : "none"); PresetRuntimeProfile presetRuntimeProfile = ActivePresetProfile(); string text3 = ((presetRuntimeProfile == null) ? ("Custom CFG " + Mathf.RoundToInt(ExtensionDistance()) + "m") : (presetRuntimeProfile.UseWorldMaximum ? (Mathf.RoundToInt(Mathf.Max(0f, ValidForestRange() - NativeTreelineHandoff())) + "m (world max)") : (Mathf.RoundToInt(presetRuntimeProfile.ExtensionDistance) + "m"))); GUI.Box(new Rect(12f, 12f, 1380f, 1000f), "New Horizons Treelines v4.6.31 Swamp Trees Default Off -- Page 1/10 (Page Up/Down to switch)"); GUI.Label(new Rect(24f, 34f, 1060f, 20f), "Build ID: NHT-4.6.31-20260717-SWAMP-TREES-DEFAULT-OFF | DLL: " + Assembly.GetExecutingAssembly().Location, _overlayStyle); GUI.Label(new Rect(24f, 54f, 1060f, 20f), "Config: " + Path.Combine(Paths.ConfigPath, "marc.donegalhorizonlift.cfg") + " | " + _duplicateDllStatus, _overlayStyle); GUI.Label(new Rect(24f, 74f, 1320f, 20f), "PRESET: " + _qualityPreset.Value.ToString() + " | H/TreeStart/Canopy " + Mathf.RoundToInt(NativeTreelineHandoff()) + "/" + Mathf.RoundToInt(EffectiveTreeCardStart()) + "/" + Mathf.RoundToInt(CanopyStart()) + "m | E actual/expected " + Mathf.RoundToInt(ExtensionDistance()) + "m/" + text3 + " | DetailedEnd " + Mathf.RoundToInt(TreeCardEnd()) + "m | " + (_presetContractValid ? "PRESET CONTRACT OK" : "PRESET CONTRACT VIOLATION"), _overlayStyle); GUI.Label(new Rect(24f, 94f, 1320f, 20f), "Final outer " + Mathf.RoundToInt(FinalForestRange()) + "m (valid max " + Mathf.RoundToInt(ValidForestRange()) + "m; " + RangeClampReason() + ") | capacity forest/tree/canopy " + MaxForestTiles() + "/" + GlobalTreeCardPlaneBudget() + "/" + GlobalCanopyPlaneBudget() + " | panic/base→effective build " + PanicTileCeiling() + "/" + BaseTilesBuiltPerFrame() + "→" + TilesBuiltPerFrame() + " upload " + BaseMaximumMeshUploadsPerFrame() + "→" + MaximumMeshUploadsPerFrame(), _overlayStyle); GUI.Label(new Rect(24f, 114f, 1320f, 20f), "Effective distances: tree-card start " + Mathf.RoundToInt(ContinuityStart()) + "m | tree-card end " + Mathf.RoundToInt(TreeCardEnd()) + "m | canopy start " + Mathf.RoundToInt(CanopyStart()) + "m | continuity end " + Mathf.RoundToInt(ContinuityEnd()) + "m | far forest end " + Mathf.RoundToInt(FarForestEndDistance()) + "m | far terrain end " + Mathf.RoundToInt(FarTerrainViewDistance()) + "m", _overlayStyle); GUI.Label(new Rect(24f, 134f, 1320f, 20f), "Effective density: cell " + ClusterCellSize().ToString("F0", CultureInfo.InvariantCulture) + "m | multiplier x" + ForestDensityMultiplier().ToString("F2", CultureInfo.InvariantCulture) + " | continuous " + (ContinuousForestCoverageEnabled() ? "ON" : "off") + " M/BF/S/Mtn/P " + ContinuousCoverageTargetForBiome((Biome)1).ToString("F2", CultureInfo.InvariantCulture) + "/" + ContinuousCoverageTargetForBiome((Biome)8).ToString("F2", CultureInfo.InvariantCulture) + "/" + ContinuousCoverageTargetForBiome((Biome)2).ToString("F2", CultureInfo.InvariantCulture) + "/" + ContinuousCoverageTargetForBiome((Biome)4).ToString("F2", CultureInfo.InvariantCulture) + "/" + ContinuousCoverageTargetForBiome((Biome)16).ToString("F2", CultureInfo.InvariantCulture), _overlayStyle); int requested; string limitReason; int num = TerrainTileLimitInfo(out requested, out limitReason); int requested2; int roomAfterTerrain; string limitReason2; int num2 = ForestTileLimitInfo(out requested2, out roomAfterTerrain, out limitReason2); GUI.Label(new Rect(24f, 154f, 1320f, 20f), "Tiles requested/built/max: terrain " + requested + "/" + _terrainTiles.Count + "/" + num + " | forest " + requested2 + "/" + _forestTiles.Count + "/" + num2 + " | panic used/max " + (num + num2) + "/" + PanicTileCeiling() + " | budget clamp " + BudgetClampReason(), _overlayStyle); GUI.Label(new Rect(24f, 174f, 1320f, 20f), "Planes used/budget/remaining: tree-card " + CountTreeCards() + "/" + GlobalTreeCardPlaneBudget() + "/" + _remainingTreeCardPlaneBudget + " | canopy " + CountCanopyCards() + "/" + GlobalCanopyPlaneBudget() + "/" + _remainingCanopyPlaneBudget + " | per tile clusters/tree/canopy " + MaximumClustersPerTile() + "/" + MaxTreeCardPlanesPerTile() + "/" + MaxCanopyPlanesPerTile(), _overlayStyle); GUI.Label(new Rect(24f, 194f, 1120f, 20f), "Provider ready/failure: " + ((_provider != null && _provider.IsReady) ? "ready" : _providerFailure) + " | World provider: " + ((_provider != null) ? _provider.ProviderName : "none") + " | reason: " + _providerSelectionReason, _overlayStyle); GUI.Label(new Rect(24f, 214f, 1120f, 20f), "Render Limits: " + _renderLimitsStatus + " | exclusion " + Mathf.RoundToInt(VisualExclusionRadius()) + "m", _overlayStyle); GUI.Label(new Rect(24f, 234f, 1320f, 20f), "Tree atlas: " + _treeAtlasStatus + " | shader: " + _treeAtlasShader + " | neutral normals " + ((_useNeutralAtlasNormals == null || _useNeutralAtlasNormals.Value) ? "ON" : "off") + " | zero/near-zero normals " + _atlasMeshZeroLengthNormals, _overlayStyle); GUI.Label(new Rect(24f, 254f, 1060f, 20f), "Canopy atlas: " + _canopyAtlasStatus + " | Canopy atlas shader: " + _canopyAtlasShader, _overlayStyle); GUI.Label(new Rect(24f, 274f, 1120f, 20f), "Biome atlases: mountain " + _mountainBiomeAtlasStatus + " (" + _mountainBiomeAtlasShader + ") | swamp " + _swampBiomeAtlasStatus + " (" + _swampBiomeAtlasShader + ") | biome card mode " + (((Object)(object)_mountainBiomeCardMaterial != (Object)null || (Object)(object)_swampBiomeCardMaterial != (Object)null) ? "active" : "inactive"), _overlayStyle); GUI.Label(new Rect(24f, 294f, 1120f, 20f), "Forest: " + (_forestContinuityEnabled.Value ? "enabled" : "disabled") + " | range " + Mathf.RoundToInt(ContinuityStart()) + "-" + Mathf.RoundToInt(ContinuityEnd()) + "m | tree cards to " + Mathf.RoundToInt(TreeCardEnd()) + "m | canopy from " + Mathf.RoundToInt(CanopyStart()) + "m | handoff exact H/O contract", _overlayStyle); GUI.Label(new Rect(24f, 314f, 1120f, 20f), "Clusters: " + CountForestClusters() + " | Tree-card planes: " + CountTreeCards() + "/" + GlobalTreeCardPlaneBudget() + " | Canopy planes: " + CountCanopyCards() + "/" + GlobalCanopyPlaneBudget() + " | density x" + ForestDensityMultiplier().ToString("F2"), _overlayStyle); GUI.Label(new Rect(24f, 334f, 1120f, 20f), "Terrain tint/shade (nearest): " + _lastTerrainTintNearestStatus + " | Camera target far clip " + Mathf.RoundToInt(CameraFarClip()), _overlayStyle); GUI.Label(new Rect(24f, 354f, 1120f, 20f), "Terrain tint/shade (farthest): " + _lastTerrainTintFarthestStatus, _overlayStyle); GUI.Label(new Rect(24f, 374f, 1120f, 20f), "Weather: " + _weatherName + " / " + _weatherClassification + " | External fog: " + _externalFogStatus, _overlayStyle); GUI.Label(new Rect(24f, 394f, 1120f, 20f), "Atmosphere: " + _hazeStatus + " | original/target/current fog " + _savedFogDensity.ToString("F4", CultureInfo.InvariantCulture) + "/" + _targetFogDensity.ToString("F4", CultureInfo.InvariantCulture) + "/" + _appliedFogDensity.ToString("F4", CultureInfo.InvariantCulture), _overlayStyle); GUI.Label(new Rect(24f, 414f, 1120f, 20f), "Map: " + ((_provider != null) ? _provider.TerrainOverlayStatus : "none") + " | " + _lastMapAlignmentStatus + " | Water: " + ((_provider != null) ? _provider.WaterSource : "none") + " | World radius: " + ((_provider != null) ? Mathf.RoundToInt(_provider.WorldRadius).ToString(CultureInfo.InvariantCulture) : "unknown") + " | valid forest W " + Mathf.RoundToInt(ValidForestRange()), _overlayStyle); GUI.Label(new Rect(24f, 434f, 1120f, 20f), "Last rebuild: " + _lastRebuildReason + " | Last atlas-material error: " + _lastAtlasMaterialError, _overlayStyle); GUI.Label(new Rect(24f, 454f, 1120f, 20f), "Support tiles: 0 permanently | Skirts: 0 permanently | Native tree handoff: off permanently | Custom colliders: 0", _overlayStyle); GUI.Label(new Rect(24f, 474f, 1120f, 20f), "Legacy config: " + _legacyConfigStatus + " | Map exploration touched: no | World mode " + _worldDataMode.Value.ToString() + " | Provider " + ((_provider != null) ? _provider.ProviderName : "none"), _overlayStyle); GUI.Label(new Rect(24f, 494f, 1120f, 20f), "Diagnostics: forest proof " + (_forestProofDiagnostic.Value ? "extra logs enabled" : "off") + " | " + _status, _overlayStyle); GUI.Label(new Rect(24f, 514f, 1120f, 20f), "Ground gate: " + (_groundAuthoritativePlacement.Value ? "ON" : "OFF") + " | exact support " + (_requireExactFootprintTerrainSupport.Value ? "ON" : "OFF") + " | max height diff " + _maxFootprintHeightDifference.Value.ToString("F1", CultureInfo.InvariantCulture) + "m", _overlayStyle); GUI.Label(new Rect(24f, 534f, 1120f, 20f), "Ground rejects: cards " + _groundGateRejectedCards + " | water " + _groundGateRejectedWater + " | unsupported " + _groundGateRejectedUnsupported + " | height mismatch " + _groundGateRejectedHeightMismatch + " | proxy/mass " + _groundGateRejectedProxy, _overlayStyle); GUI.Label(new Rect(24f, 554f, 1260f, 20f), "Effective (post-clamp): continuity end " + Mathf.RoundToInt(ContinuityEnd()) + "m | queue radius " + Mathf.RoundToInt(ContinuityEnd() + ContinuityTileSize()) + "m | tree card end " + Mathf.RoundToInt(TreeCardEnd()) + "m | canopy from " + Mathf.RoundToInt(CanopyStart()) + "m | far terrain " + Mathf.RoundToInt(FarTerrainViewDistance()) + "m", _overlayStyle); int requested3; int roomAfterTerrain2; string limitReason3; int num3 = ForestTileLimitInfo(out requested3, out roomAfterTerrain2, out limitReason3); GUI.Label(new Rect(24f, 574f, 1300f, 20f), "Effective: density x" + ForestDensityMultiplier().ToString("F2", CultureInfo.InvariantCulture) + " | tree budget " + GlobalTreeCardPlaneBudget() + " | canopy budget " + GlobalCanopyPlaneBudget() + " | forest tiles " + requested3 + " -> " + num3 + " (" + limitReason3 + ") | terrain tiles " + MaxTerrainTiles() + " | panic " + PanicTileCeiling(), _overlayStyle); GUI.Label(new Rect(24f, 594f, 1260f, 20f), "Horizon Clarity: " + ((_enableHorizonClarity.Value && _reduceHorizonHaze.Value) ? "on" : "off") + " | haze str " + _horizonHazeStrength.Value.ToString("F2", CultureInfo.InvariantCulture) + " | terrain fade " + _terrainDistanceFadeStrength.Value.ToString("F2", CultureInfo.InvariantCulture) + " | forest fade " + _forestDistanceFadeStrength.Value.ToString("F2", CultureInfo.InvariantCulture) + " | weather x" + ClarityWeatherScale().ToString("F2", CultureInfo.InvariantCulture) + " (" + _weatherClassification + ")", _overlayStyle); GUI.Label(new Rect(24f, 614f, 1260f, 20f), "Clarity terrain contrast/dark " + FarTerrainContrast().ToString("F2", CultureInfo.InvariantCulture) + "/" + FarTerrainDarkness().ToString("F2", CultureInfo.InvariantCulture) + " | forest contrast/dark " + FarForestContrast().ToString("F2", CultureInfo.InvariantCulture) + "/" + FarForestDarkness().ToString("F2", CultureInfo.InvariantCulture) + " | tree/canopy alpha " + FarTreeAlpha().ToString("F2", CultureInfo.InvariantCulture) + "/" + FarCanopyAlpha().ToString("F2", CultureInfo.InvariantCulture) + " | fog influence " + _weatherFogInfluence.Value.ToString("F2", CultureInfo.InvariantCulture), _overlayStyle); GUI.Label(new Rect(24f, 634f, 1300f, 20f), "Biome candidates/accepted: swamp " + _swampCandidates + "/" + _swampAccepted + " | mountain " + _mountainCandidates + "/" + _mountainAccepted + " | plains " + _plainsCandidates + "/" + _plainsAccepted + " | mixed " + _mixedCandidates + " | swamp atlas " + (HasTreeCardMaterialForBiome((Biome)2) ? "on" : "off") + " | mountain atlas " + (HasTreeCardMaterialForBiome((Biome)4) ? "on" : "off"), _overlayStyle); GUI.Label(new Rect(24f, 654f, 1340f, 20f), "Exact biome tree multipliers M/BF/S/Mtn/P/Mist/Ash/North " + BiomeForestMultiplier((Biome)1).ToString("F2", CultureInfo.InvariantCulture) + "/" + BiomeForestMultiplier((Biome)8).ToString("F2", CultureInfo.InvariantCulture) + "/" + BiomeForestMultiplier((Biome)2).ToString("F2", CultureInfo.InvariantCulture) + "/" + BiomeForestMultiplier((Biome)4).ToString("F2", CultureInfo.InvariantCulture) + "/" + BiomeForestMultiplier((Biome)16).ToString("F2", CultureInfo.InvariantCulture) + "/" + BiomeForestMultiplier((Biome)512).ToString("F2", CultureInfo.InvariantCulture) + "/" + BiomeForestMultiplier((Biome)32).ToString("F2", CultureInfo.InvariantCulture) + "/" + BiomeForestMultiplier((Biome)64).ToString("F2", CultureInfo.InvariantCulture), _overlayStyle); GUI.Label(new Rect(24f, 674f, 1320f, 20f), "Card Ground Lock: " + (_enableCardGroundLock.Value ? _cardBaseHeightMode.Value.ToString() : "OFF") + " | lowered " + _groundLockLowered + " | rejected floating " + _groundLockRejectedFloat + " | distant unsupported " + _groundLockRejectedDistantUnsupported + " | float tol " + _finalBaseFloatTolerance.Value.ToString("F2", CultureInfo.InvariantCulture) + "m", _overlayStyle); GUI.Label(new Rect(24f, 694f, 1320f, 20f), "Ground-lock rejects by type: tree/biome " + _groundLockRejectedTree + " | canopy " + _groundLockRejectedCanopy + " | proxy/mass " + _groundLockRejectedProxy, _overlayStyle); GUI.Label(new Rect(24f, 714f, 1360f, 20f), "Universal no-floating: attempted " + _noFloatPlacementsAttempted + " | accepted " + _noFloatPlacementsAccepted + " | below water " + _noFloatRejectedBelowWater + " | visible-land ratio " + _noFloatRejectedVisibleLandRatio + " | coastline edge " + _noFloatRejectedCoastlineEdge, _overlayStyle); GUI.Label(new Rect(24f, 734f, 1360f, 20f), "No-floating rejects: uncertain support " + _noFloatRejectedUncertainSupport + " | final floating " + _noFloatRejectedFinalFloating + " | lowered " + _groundLockLowered + " | sunk " + _noFloatCardsSunkIntoGround + " | post-lock lift detected " + _postLockLiftDetectedCount, _overlayStyle); GUI.Label(new Rect(24f, 754f, 1360f, 20f), "No-floating by type: tree/biome " + _noFloatRejectedTreeBiome + " | canopy " + _noFloatRejectedCanopy + " | proxy/mass " + _noFloatRejectedProxyMass + " | fill/duplicate " + _noFloatRejectedFillDuplicate, _overlayStyle); GUI.Label(new Rect(24f, 774f, 1360f, 20f), "Visible land gate: " + (_enableVisibleLandSupportGate.Value ? "ON" : "OFF") + " | ratio " + _requiredVisibleLandSampleRatio.Value.ToString("F2", CultureInfo.InvariantCulture) + " | coast ratio " + _coastlineVisibleLandSampleRatio.Value.ToString("F2", CultureInfo.InvariantCulture) + " | min samples " + _minimumVisibleLandSamples.Value + " | min base above water " + _minimumBaseAboveWater.Value.ToString("F2", CultureInfo.InvariantCulture) + "m / swamp " + _swampMinimumBaseAboveWater.Value.ToString("F2", CultureInfo.InvariantCulture) + "m", _overlayStyle); GUI.Label(new Rect(24f, 794f, 1360f, 20f), "Ground-lock final: base mode " + _cardBaseHeightMode.Value.ToString() + " | max base above ground " + _maxCardBaseAboveGround.Value.ToString("F2", CultureInfo.InvariantCulture) + "m | float tolerance " + _finalBaseFloatTolerance.Value.ToString("F2", CultureInfo.InvariantCulture) + "m | fail closed " + (_failClosedIfSupportUncertain.Value ? "ON" : "OFF") + " | debug bases " + (_debugDrawCardBases.Value ? "ON" : "OFF"), _overlayStyle); GUI.Label(new Rect(24f, 814f, 1360f, 20f), "Tree/biome no-floating: attempts " + _treeBiomeNoFloatAttempts + " | validated " + _treeBiomeNoFloatValidated + " | rejected by no-floating " + _treeBiomeRejectedNoFloating + " | missing validation " + _treeBiomeRejectedValidationMissing, _overlayStyle); GUI.Label(new Rect(24f, 834f, 1360f, 20f), "Tree/biome reject details: below water " + _treeBiomeRejectedBelowWater + " | visible land ratio/coast " + _treeBiomeRejectedVisibleLandRatio + " | after final mesh guard " + _treeBiomeRejectedAfterMeshGuard, _overlayStyle); GUI.Label(new Rect(24f, 854f, 1360f, 20f), "Final mesh guard: AddAtlasCard blocked " + _addAtlasCardBlockedCount + " | post-validation lift blocked " + _postValidationLiftBlockedCount + " | raw AddAtlasCard path disabled", _overlayStyle); GUI.Label(new Rect(24f, 874f, 1360f, 20f), "Root anchor: attempts " + _rootAnchorAttempts + " | accepted " + _rootAnchorAccepted + " | rejected water " + _rootAnchorRejectedWater + " | unsupported " + _rootAnchorRejectedUnsupported + " | dry ratio " + _rootAnchorRejectedDryRatio + " | float height " + _rootAnchorRejectedFloatHeight + " | water channel " + _rootAnchorRejectedWaterChannel + " | missing blocked " + _rootAnchorMissingValidationBlocked, _overlayStyle); GUI.Label(new Rect(24f, 894f, 1360f, 20f), "Root by biome accepted/rejected: swamp " + _swampRootAccepted + "/" + _swampRootRejected + " | mountain " + _mountainRootAccepted + "/" + _mountainRootRejected + " | plains " + _plainsRootAccepted + "/" + _plainsRootRejected + " | mixed " + _mixedRootAccepted + "/" + _mixedRootRejected, _overlayStyle); GUI.Label(new Rect(24f, 914f, 1360f, 20f), "Root mesh guard: root missing blocked " + _treeCardMeshGuardBlockedRootMissing + " | tree mesh bottoms corrected " + _treeCardMeshBottomCorrected + " | post-root lift blocked " + _treeCardPostRootLiftBlocked, _overlayStyle); GUI.Label(new Rect(24f, 934f, 1360f, 20f), "Root grounding: " + (_enableTrunkAnchorGrounding.Value ? "ON" : "OFF") + " | mode " + _rootAnchorMode.Value.ToString() + " | sample radius " + _rootAnchorSampleRadius.Value.ToString("F2", CultureInfo.InvariantCulture) + "m | dry ratio " + _rootAnchorRequiredDryRatio.Value.ToString("F2", CultureInfo.InvariantCulture) + " | float tolerance " + _rootAnchorFloatTolerance.Value.ToString("F2", CultureInfo.InvariantCulture) + "m", _overlayStyle); GUI.Label(new Rect(24f, 954f, 1340f, 20f), "Swamp handoff: pre-band bypass REMOVED (v4.5.4) -- swamp cards now gated at the same start as everything else | legacy start cfg " + Mathf.RoundToInt(_swampTreeCardStartDistance.Value) + "m (ignored) end " + Mathf.RoundToInt(SwampTreeCardEnd((Biome)2)) + "m | emitted " + _closeSwampEmitted + " rej water " + _closeSwampRejectedWater + " root " + _closeSwampRejectedRoot + " | sample retries used " + _treeSampleRetriesUsed, _overlayStyle); GUI.Label(new Rect(24f, 974f, 1340f, 20f), "Coastal recovery: " + ((_enableCoastalLandRecovery != null && _enableCoastalLandRecovery.Value) ? "ON" : "off") + " | searches/accepted " + _coastalLandRecoverySearches + "/" + _coastalLandRecoveryAccepted + " | foliage-overhang accepted " + _coastalFoliageOverhangPlacementsAccepted + " | trunk safety width " + ((_coastalDetailedTreeWaterSafetyWidth != null) ? _coastalDetailedTreeWaterSafetyWidth.Value.ToString("F1", CultureInfo.InvariantCulture) : "3.5") + "m | BF/Meadows near subclusters " + ((_blackForestNearMinimumSubclusters != null) ? _blackForestNearMinimumSubclusters.Value.ToString(CultureInfo.InvariantCulture) : "3") + "/" + ((_meadowsNearMinimumSubclusters != null) ? _meadowsNearMinimumSubclusters.Value.ToString(CultureInfo.InvariantCulture) : "2"), _overlayStyle); } private void DrawTreelinePanel() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0589: Unknown result type (might be due to invalid IL or missing references) //IL_058e: Unknown result type (might be due to invalid IL or missing references) //IL_055e: Unknown result type (might be due to invalid IL or missing references) //IL_0563: Unknown result type (might be due to invalid IL or missing references) //IL_05d6: Unknown result type (might be due to invalid IL or missing references) float num = 12f; float num2 = 12f; GUI.Box(new Rect(num, num2, 1380f, 300f), "New Horizons Treelines v4.6.31 -- Native Treeline Diagnostics (page 2/10)"); float nearestEnabledForestChunkEdge = _nearestEnabledForestChunkEdge; float num3 = NativeTreelineHandoff(); float num4 = ((nearestEnabledForestChunkEdge < float.MaxValue) ? (nearestEnabledForestChunkEdge - num3) : float.NaN); float num5 = ((_nativeTreelineSeamTolerance != null) ? _nativeTreelineSeamTolerance.Value : 4f); string text = (float.IsNaN(num4) ? "TREELINE GAP (no enabled card edge currently measured)" : ((num4 < -0.05f) ? ("TREELINE INSIDE CALIBRATION (edge " + (0f - num4).ToString("F1", CultureInfo.InvariantCulture) + "m inside H)") : ((!(num4 <= num5)) ? ("TREELINE GAP (" + num4.ToString("F1", CultureInfo.InvariantCulture) + "m beyond seam tolerance)") : "STRICT TREELINE OK"))); string[] array = new string[13] { "Public name: New Horizons Treelines (development build v4.6.31)", "Native treeline mode: " + ((_nativeTreelineMode != null) ? _nativeTreelineMode.Value.ToString() : "AutoDetect") + " | source: " + _nativeTreeRangeSource, "Raw native radius: " + Mathf.RoundToInt(RawNativeTreelineRadius()) + "m | handoff offset " + ((_nativeTreelineHandoffOffset != null) ? _nativeTreelineHandoffOffset.Value : 0f).ToString("F0", CultureInfo.InvariantCulture) + "m => H " + Mathf.RoundToInt(num3) + "m", "Strict enforcement: " + ((_enforceStrictCalibratedTreeline != null && _enforceStrictCalibratedTreeline.Value) ? "ON (O forced to 0)" : "off") + " | Seam overlap O: " + Mathf.RoundToInt(NativeTreelineSeamOverlap()) + "m | Seam tolerance: " + num5.ToString("F0", CultureInfo.InvariantCulture) + "m | Authoritative TreeStart: " + Mathf.RoundToInt(EffectiveTreeCardStart()) + "m", "Requested extension E: " + Mathf.RoundToInt(ExtensionDistance()) + "m | Final world-capped extension: " + Mathf.RoundToInt(FinalForestRange() - num3) + "m", "Final outer boundary (H+E capped): " + Mathf.RoundToInt(FinalForestRange()) + "m | Provider/world clamp reason: " + RangeClampReason(), "Nearest enabled static card edge: " + ((nearestEnabledForestChunkEdge < float.MaxValue) ? (Mathf.RoundToInt(nearestEnabledForestChunkEdge) + "m") : "none visible") + " | Measured handoff gap (edge - H): " + (float.IsNaN(num4) ? "n/a" : (((num4 >= 0f) ? "+" : "") + num4.ToString("F1", CultureInfo.InvariantCulture) + "m")), "Boundary chunk size: " + Mathf.RoundToInt(BoundaryTreelineChunkSize()) + "m (handoff band) | Normal chunk size: " + Mathf.RoundToInt(NormalForestChunkSize()) + "m", "Fixed chunks built: " + _forestChunkCount + " | Visible chunks: " + Mathf.Max(0, _forestChunkCount - _forestNearCulledChunkCount) + " | Inner-hidden: " + _forestNearCulledChunkCount + " | Outer-hidden: n/a (unloaded, not tracked live)", "Pending slider/H rebuild: " + ((_pendingTreelineRebuildDebounce > 0f) ? (_pendingTreelineRebuildDebounce.ToString("F1", CultureInfo.InvariantCulture) + "s") : "none") + " | Last rebuild duration: " + (_rebuildTimingPending ? "in progress" : (_lastRebuildDurationSeconds.ToString("F2", CultureInfo.InvariantCulture) + "s")), "Mixed cards emitted: " + CountTreeCards() + " | Canopy cards emitted: " + CountCanopyCards() + " | Swamp cards emitted: " + _swampAccepted + " | Swamp renderers enabled: " + _swampRenderersEnabled, (_staticPlacementOk ? "STATIC PLACEMENT OK" : "STATIC PLACEMENT: TRANSFORM MOVED (a chunk's root moved from its creation position)") + " || " + text, "Calibration: " + ((_enableCalibrationMode != null && _enableCalibrationMode.Value) ? "gate ON" : "gate OFF (Enable Calibration Mode = false)") + " | mode active: " + (_calibrationModeActive ? ("YES (" + ((object)_calibrationToggleKey.Value/*cast due to .constrained prefix*/).ToString() + " to exit)") : ("no (" + ((_calibrationToggleKey != null) ? ((object)_calibrationToggleKey.Value/*cast due to .constrained prefix*/).ToString() : "F9") + " to start)")) }; for (int i = 0; i < array.Length; i++) { GUI.Label(new Rect(num + 12f, num2 + 22f + (float)i * 20f, 1356f, 20f), array[i], _overlayStyle); } } private void DrawSwampPanel() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) float num = 12f; float num2 = 324f; GUI.Box(new Rect(num, num2, 1380f, 250f), "Swamp Tree Card Diagnostics"); string[] array = new string[11] { "Swamp atlas: " + _swampBiomeAtlasStatus + " (" + _swampBiomeAtlasShader + ") | Swamp material: " + (((Object)(object)_swampBiomeCardMaterial != (Object)null) ? "loaded (dedicated swamp textures)" : (((Object)(object)_treeCardMaterial != (Object)null) ? "MISSING -- using mixed atlas fallback" : "MISSING -- no fallback available")), "Raw candidates / biome matches: " + _swampCandidates + " (same counter -- biome is already known when a candidate is counted in this pipeline)", "Passed density/slope: " + _swampPassedDensity + " | Rejected threshold: " + _swampRejectedThreshold + " | Rejected slope: " + _swampRejectedSlope, "Passed inner/outer boundary: " + _swampCandidates + " (cells outside the boundary never reach biome sampling, so this is the same as raw candidates)", "No-floating attempts: " + _swampNoFloatAttempts + " | Rejected water: " + _swampRejectedWater + " | visible-land ratio: " + _swampRejectedVisibleLandRatio + " | coastline: " + _swampRejectedCoastline, "Rejected support/ground-lock: " + _swampRejectedSupport + " | Rejected final floating: " + _swampRejectedFinalFloating, "Root anchor rejected (total): " + _swampRejectedRootAnchor + " | dry ratio: " + _swampRejectedRootDryRatio + " | water channel: " + _swampRejectedWaterChannel, "Accepted: " + _swampAccepted + " | Cards emitted (tree-card plane count): " + _closeSwampEmitted, "Chunks built with swamp content: " + _swampChunksBuilt + " | Renderers created: " + _swampRenderersCreated + " | Renderers enabled now: " + _swampRenderersEnabled, "Inner-culled (live): " + _swampInnerCulled + " | Outer-culled (live): " + _swampOuterCulled, "Dominant swamp rejection reason: " + DominantSwampRejectionReason() }; for (int i = 0; i < array.Length; i++) { GUI.Label(new Rect(num + 12f, num2 + 22f + (float)i * 20f, 1356f, 20f), array[i], _overlayStyle); } } private void DrawCalibrationActivationBanner() { //IL_0173: 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_001d: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (_calibrationBannerStyle == null) { _calibrationBannerStyle = new GUIStyle(GUI.skin.box); _calibrationBannerStyle.fontSize = 22; _calibrationBannerStyle.normal.textColor = new Color(1f, 0.85f, 0.1f, 1f); _calibrationBannerStyle.wordWrap = true; } float num = 620f; float num2 = 190f; float num3 = ((float)Screen.width - num) * 0.5f; float num4 = 60f; string text = "NEW HORIZONS TREELINE CALIBRATION ACTIVE\n\nGuide radius: " + Mathf.RoundToInt(_calibrationRadius) + " metres\n\nUse " + KeyLabel(_calibrationToggleKey) + " to exit\nUse " + KeyLabel(_calibrationIncrease1mKey) + "/" + KeyLabel(_calibrationDecrease1mKey) + " to adjust by 1m\nUse " + KeyLabel(_calibrationDecrease5mKey) + " and " + KeyLabel(_calibrationIncrease5mKey) + " to adjust by 5m\nUse " + KeyLabel(_calibrationDecrease25mKey) + " and " + KeyLabel(_calibrationIncrease25mKey) + " to adjust by 25m\nPress " + KeyLabel(_calibrationSaveKey) + " to save"; GUI.Box(new Rect(num3, num4, num, num2), text, _calibrationBannerStyle); } private void DrawCalibrationGateWarningBanner() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (_calibrationBannerStyle == null) { _calibrationBannerStyle = new GUIStyle(GUI.skin.box); _calibrationBannerStyle.fontSize = 22; _calibrationBannerStyle.normal.textColor = new Color(1f, 0.85f, 0.1f, 1f); _calibrationBannerStyle.wordWrap = true; } GUIStyle val = new GUIStyle(_calibrationBannerStyle); val.normal.textColor = new Color(1f, 0.35f, 0.25f, 1f); float num = 620f; float num2 = 90f; float num3 = ((float)Screen.width - num) * 0.5f; float num4 = 60f; string text = "Calibration is disabled in the CFG.\nSet Enable Calibration Mode = true."; GUI.Box(new Rect(num3, num4, num, num2), text, val); } private void DrawCalibrationOverlay() { //IL_0030: 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_03dd: Unknown result type (might be due to invalid IL or missing references) if (_overlayStyle != null) { float num = Mathf.Max(12f, (float)Screen.height - 250f); GUI.Box(new Rect(12f, num, 680f, 230f), "Native Treeline Calibration (diagnostic only -- New Horizons cards hidden)"); CalibrationSampleStats stats; bool flag = TryComputeCalibrationSampleStats(out stats); string text = (flag ? ("Samples " + stats.Count + " | min " + Mathf.RoundToInt(stats.Min) + "m max " + Mathf.RoundToInt(stats.Max) + "m median " + Mathf.RoundToInt(stats.Median) + "m | P25 " + Mathf.RoundToInt(stats.P25) + "m P75 " + Mathf.RoundToInt(stats.P75) + "m | MAD " + stats.MedianAbsoluteDeviation.ToString("F1", CultureInfo.InvariantCulture) + "m | coverage " + Mathf.RoundToInt(stats.DirectionalCoverageDegrees) + " deg") : ("No directional samples recorded yet (optional -- " + ((_calibrationRecordSampleKey != null) ? ((object)_calibrationRecordSampleKey.Value/*cast due to .constrained prefix*/).ToString() : "R") + " to record one facing a dense forest edge)")); string text2 = (flag ? (" | Suggested conservative radius (P25): " + Mathf.RoundToInt(stats.P25) + "m") : ""); string[] array = new string[6] { "Guide radius: " + Mathf.RoundToInt(_calibrationRadius) + "m | Guide points: " + _calibrationGuidePointCount + " | Origin mode: " + _calibrationOriginMode, "Origin: " + _lastCalibrationGuideOrigin.x.ToString("F0", CultureInfo.InvariantCulture) + " / " + _lastCalibrationGuideOrigin.y.ToString("F0", CultureInfo.InvariantCulture) + " / " + _lastCalibrationGuideOrigin.z.ToString("F0", CultureInfo.InvariantCulture), text + text2, "+-1m: " + KeyLabel(_calibrationIncrease1mKey) + "/" + KeyLabel(_calibrationDecrease1mKey) + " +-5m: " + KeyLabel(_calibrationIncrease5mKey) + "/" + KeyLabel(_calibrationDecrease5mKey) + " +-25m: " + KeyLabel(_calibrationIncrease25mKey) + "/" + KeyLabel(_calibrationDecrease25mKey), "Save: " + KeyLabel(_calibrationSaveKey) + " (writes Native Treeline Calibrated Radius + switches mode to ManualCalibrated, no rebuild needed) | Reset: " + KeyLabel(_calibrationResetKey), "Record sample: " + KeyLabel(_calibrationRecordSampleKey) + " | Clear samples: " + KeyLabel(_calibrationClearSamplesKey) + " | Exit calibration: " + KeyLabel(_calibrationToggleKey) }; for (int i = 0; i < array.Length; i++) { GUI.Label(new Rect(24f, num + 22f + (float)i * 20f, 656f, 40f), array[i], _overlayStyle); } } } private void DrawCalibrationDiagnosticsPanel() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_0586: Unknown result type (might be due to invalid IL or missing references) float num = 12f; float num2 = 586f; GUI.Box(new Rect(num, num2, 1380f, 280f), "Calibration Activation & Rendering Diagnostics"); bool flag = _enableCalibrationMode != null && _enableCalibrationMode.Value; bool flag2 = (Object)(object)_calibrationGuideObject != (Object)null; bool flag3 = flag2 && _calibrationGuideObject.activeInHierarchy; bool flag4 = (Object)(object)_calibrationGuideRenderer != (Object)null; bool flag5 = flag4 && ((Renderer)_calibrationGuideRenderer).enabled; string text = (((Object)(object)_calibrationGuideMaterial != (Object)null) ? ((Object)_calibrationGuideMaterial).name : "null"); string text2 = (((Object)(object)_calibrationGuideMaterial != (Object)null) ? ColorUtility.ToHtmlStringRGBA(_calibrationGuideMaterial.color) : "n/a"); float num3 = ((_lastCalibrationGuideRebuildRealtime >= 0f) ? (Time.realtimeSinceStartup - _lastCalibrationGuideRebuildRealtime) : (-1f)); string[] array = new string[11] { "Calibration CFG enabled: " + (flag ? "YES" : "NO") + " | Calibration active: " + (_calibrationModeActive ? "YES" : "no") + " | Toggle key detected this frame: " + (_calibrationToggleKeyDetectedThisFrame ? "YES" : "no") + " | Toggle key: " + KeyLabel(_calibrationToggleKey), "Calibration origin mode: " + _calibrationOriginMode + " | Origin X/Y/Z: " + _lastCalibrationGuideOrigin.x.ToString("F1", CultureInfo.InvariantCulture) + " / " + _lastCalibrationGuideOrigin.y.ToString("F1", CultureInfo.InvariantCulture) + " / " + _lastCalibrationGuideOrigin.z.ToString("F1", CultureInfo.InvariantCulture) + " | Calibration radius: " + Mathf.RoundToInt(_calibrationRadius) + "m", "Guide GameObject exists: " + (flag2 ? "YES" : "no") + " | Guide active in hierarchy: " + (flag3 ? "YES" : "no") + " | LineRenderer exists: " + (flag4 ? "YES" : "no") + " | LineRenderer enabled: " + (flag5 ? "YES" : "no"), "Guide point count: " + _calibrationGuidePointCount + " | Valid terrain samples: " + _calibrationValidSamples + " | Failed terrain samples: " + _calibrationFailedSamples, "Sampled height min/max: " + (float.IsNaN(_calibrationMinSampledHeight) ? "n/a" : _calibrationMinSampledHeight.ToString("F1", CultureInfo.InvariantCulture)) + " / " + (float.IsNaN(_calibrationMaxSampledHeight) ? "n/a" : _calibrationMaxSampledHeight.ToString("F1", CultureInfo.InvariantCulture)), "Guide material: " + text + " | Guide shader: " + _calibrationGuideShaderName + " | Guide colour (RGBA hex): " + text2, "Guide line width: " + ((_calibrationGuideLineWidth != null) ? _calibrationGuideLineWidth.Value.ToString("F1", CultureInfo.InvariantCulture) : "?") + "m | Guide height offset: " + ((_calibrationGuideHeightOffset != null) ? _calibrationGuideHeightOffset.Value.ToString("F1", CultureInfo.InvariantCulture) : "?") + "m", "Vertical marker count: " + _calibrationMarkerRenderers.Count + " (+1 facing marker) | Show markers: " + ((_showCalibrationVerticalMarkers != null && _showCalibrationVerticalMarkers.Value) ? "ON" : "OFF") + " | Marker height: " + ((_calibrationMarkerHeight != null) ? _calibrationMarkerHeight.Value.ToString("F0", CultureInfo.InvariantCulture) : "?") + "m", "Test guide enabled: " + ((_showCalibrationTestGuide != null && _showCalibrationTestGuide.Value) ? ("YES (radius " + ((_calibrationTestGuideRadius != null) ? Mathf.RoundToInt(_calibrationTestGuideRadius.Value).ToString(CultureInfo.InvariantCulture) : "?") + "m)") : "no"), "Last guide rebuild: " + ((num3 < 0f) ? "never" : (num3.ToString("F1", CultureInfo.InvariantCulture) + "s ago")), "Last calibration exception: " + _lastCalibrationException }; for (int i = 0; i < array.Length; i++) { GUI.Label(new Rect(num + 12f, num2 + 22f + (float)i * 20f, 1356f, 20f), array[i], _overlayStyle); } } private void ComputeForestChunkTierCounts(out int boundaryCount, out int normalCount, out int farCount) { boundaryCount = 0; normalCount = 0; farCount = 0; float num = BoundaryTreelineChunkSize(); float num2 = NormalForestChunkSize(); foreach (ForestTile value in _forestTiles.Values) { for (int i = 0; i < value.Chunks.Count; i++) { float size = value.Chunks[i].Size; if (Mathf.Abs(size - num) < 0.5f) { boundaryCount++; } else if (Mathf.Abs(size - num2) < 0.5f) { normalCount++; } else { farCount++; } } } } private void DrawForestStreamingPanel() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_138d: Unknown result type (might be due to invalid IL or missing references) float num = 12f; float num2 = 12f; GUI.Box(new Rect(num, num2, 1380f, 1060f), "New Horizons Treelines v4.6.31 -- Forest Streaming Diagnostics (page 3/10)"); ComputeForestChunkTierCounts(out var boundaryCount, out var normalCount, out var farCount); long tileKey = TileKey(Mathf.FloorToInt(_buildAnchor.x / ContinuityTileSize()), Mathf.FloorToInt(_buildAnchor.z / ContinuityTileSize())); TryGetForestTileWorkState(tileKey, out var state); int num3 = 0; foreach (ForestTile value in _forestTileCache.Values) { num3 += value.Chunks.Count * 5; } float num4 = ((_forestChunkBuildSampleCount > 0) ? ((float)(_forestChunkBuildMsSum / (double)_forestChunkBuildSampleCount)) : 0f); bool flag = _enableIncrementalForestStreaming == null || _enableIncrementalForestStreaming.Value; long num5 = 0L; long num6 = 0L; long num7 = 0L; int num8 = 0; for (int i = 0; i < 5; i++) { num5 += _coverageAuditedCellsByRing[i]; num6 += _coverageRemainingCellsByRing[i]; num7 += _coverageUncoveredCellsByRing[i]; } for (int j = 0; j < _coverageRepairQueue.Count; j++) { if (_coverageRepairQueue[j].CoastalSearchActive) { num8++; } } float nearestEnabledForestChunkEdge = _nearestEnabledForestChunkEdge; float num9 = ((nearestEnabledForestChunkEdge < float.MaxValue) ? (nearestEnabledForestChunkEdge - NativeTreelineHandoff()) : float.NaN); bool flag2 = !float.IsNaN(num9) && num9 >= 0f - NativeTreelineSeamOverlap() - 0.5f; string[] array = new string[49] { "Incremental streaming enabled: " + (flag ? "YES" : "NO (legacy full teardown fallback active)") + " | Adaptive governor: " + (AdaptiveHighPresetGovernorActive() ? "ON" : "off") + " (" + _adaptiveGovernorState + ") | Atlas barrier active/was active: " + (_forestAtlasBarrierActive ? "YES" : "no") + "/" + (_forestAtlasBarrierEverActive ? "yes" : "no"), "Desired chunk count: " + _forestDesiredChunkCount + " | Existing active chunks: " + _forestTiles.Count + " | Retained unchanged (last sync): " + _forestRetainedUnchangedCount, "Queued to add (last sync): " + _forestQueuedAddCount + " | Pending generation jobs (live): " + _forestAddQueue.Count + " | Queued to remove (last sync): " + _forestQueuedRemoveCount, "Visible chunks: " + Mathf.Max(0, _forestChunkCount - _forestNearCulledChunkCount) + " of " + _forestChunkCount + " built | Boundary(" + Mathf.RoundToInt(BoundaryTreelineChunkSize()) + "m): " + boundaryCount + " | Normal(" + Mathf.RoundToInt(NormalForestChunkSize()) + "m): " + normalCount + " | Far-merged: " + farCount + ((_forestFarChunkMergeEnabled != null && _forestFarChunkMergeEnabled.Value) ? "" : " (batching disabled)"), "Pooled/cached tiles: " + _forestTileCache.Count + " | Pooled meshes (est.): " + num3 + " | Estimated cache memory: " + EstimateForestCacheMemoryMb().ToString("F1", CultureInfo.InvariantCulture) + " MB", "Cache hits: " + _forestCacheHits + " | Cache misses: " + _forestCacheMisses + " | Cache evictions: " + _forestCacheEvictions + " | Activated/deferred this frame: " + _forestCacheActivationsThisFrame + "/" + _forestCacheActivationsDeferredThisFrame, "Pending forest jobs: " + _forestAddQueue.Count + " | Active resumable build: " + _forestActiveResumableJobs + " | Pending retirement jobs: " + _forestRetirementQueue.Count + " | Cancelled obsolete jobs: " + _forestCancelledObsoleteJobs + " | Permanently failed jobs: " + _forestFailedJobsPermanent, "Chunks built this frame: " + _forestChunksBuiltThisFrame + " | Meshes uploaded this frame: " + _forestMeshesUploadedThisFrame + " | Chunks retired this frame: " + _forestChunksRetiredThisFrame, "Generation time this frame: " + _forestGenerationTimeThisFrameMs.ToString("F2", CultureInfo.InvariantCulture) + "ms | Effective budget: " + EffectiveForestGenerationBudgetMs().ToString("F2", CultureInfo.InvariantCulture) + "ms | Retirement: " + _forestRetirementTimeThisFrameMs.ToString("F2", CultureInfo.InvariantCulture) + "ms", "Frame avg/current: " + _adaptiveAverageFrameMs.ToString("F2", CultureInfo.InvariantCulture) + "/" + (Time.unscaledDeltaTime * 1000f).ToString("F2", CultureInfo.InvariantCulture) + "ms | Pressure: " + _adaptivePressure.ToString("F2", CultureInfo.InvariantCulture) + " | Effective tiles/uploads/activations: " + TilesBuiltPerFrame() + "/" + MaximumMeshUploadsPerFrame() + "/" + EffectiveMaximumChunkActivationsPerFrame(), "Average tile-build: " + num4.ToString("F2", CultureInfo.InvariantCulture) + "ms | Longest: " + _forestLongestChunkBuildMs.ToString("F2", CultureInfo.InvariantCulture) + "ms | Reinforcement deferred: " + _reinforcementJobsDeferredThisFrame + " | Last hitch: " + _forestLastMajorHitch, "Current generation epoch: " + _forestGenerationEpoch + " | Generation paused last frame: " + (_forestPausedPreviousFrame ? "YES" : "no") + " | Terrain build frames deferred: " + _terrainBuildFramesDeferredForPerformance, "Last rebuild reason: " + _lastRebuildReason, "Last incremental update reason: " + _lastIncrementalUpdateReason, (_forestDeterministicRestoreOk ? "DETERMINISTIC RESTORE OK" : "DETERMINISTIC RESTORE VIOLATION") + " (" + _forestDeterministicRestoreDetail + ")", (_staticPlacementOk ? "STATIC PLACEMENT OK" : "STATIC PLACEMENT: TRANSFORM MOVED") + " || " + ((_forestHandoffOk && flag2 && HandoffFillCoverageStatus().StartsWith("HANDOFF COVERAGE OK", StringComparison.Ordinal)) ? "HANDOFF COVERAGE OK" : "HANDOFF COVERAGE INSUFFICIENT"), "-- Bounded tile generation (v4.6.15 Task 2) --", "Active job: " + _forestActiveResumableJobs + " (" + _forestCurrentJobStage + ") | Candidates processed this frame: " + _forestCandidatesProcessedThisFrame + " | Grounding samples this frame: " + _forestGroundingSamplesThisFrame, "Mesh vertices this frame: " + _forestMeshVerticesThisFrame + " | Longest single step: " + _forestLongestResumableStepMs.ToString("F1", CultureInfo.InvariantCulture) + "ms | Completed tiles: " + _forestCompletedTilesTotal + " | Cancelled jobs: " + _forestCancelledJobsTotal + " | Deferred uploads: " + _forestDeferredUploadsTotal, "Candidate cap requested/effective: " + ((_maximumCandidateCellsPerTileBuild != null) ? _maximumCandidateCellsPerTileBuild.Value : 900) + "/" + EffectiveMaximumCandidateCellsPerTileBuild() + " | Tiles that hit the cap: " + _forestCandidateCapHitCount, "-- Startup admission / hitch guard (v4.6.18) --", "Startup guard: " + (StartupHitchGuardActive() ? "ACTIVE" : "off") + " | Atlas-ready age: " + SecondsSinceForestAtlasReady().ToString("F1", CultureInfo.InvariantCulture) + "s | Deferred forest/terrain/repair frames: " + _startupForestFramesDeferred + "/" + _startupTerrainFramesDeferred + "/" + _startupCoverageRepairFramesDeferred, "-- Bootstrap / starvation protection (v4.6.15 Task 3) --", "Bootstrapping: " + (_forestBootstrapActiveLastFrame ? "YES" : "no") + " | Visible mod chunks: " + SumRingVisibleChunks() + " | Seconds since last primary progress: " + (Time.realtimeSinceStartup - _lastPrimaryProgressRealtime).ToString("F2", CultureInfo.InvariantCulture), "-- Handoff-first diagnostics (v4.6.15 Task 4) --", BuildHandoffDiagnosticsLine1(), BuildHandoffDiagnosticsLine2(), HandoffActiveCoverageOk() ? "HANDOFF COVERAGE OK" : "HANDOFF COVERAGE INSUFFICIENT", "-- Retention / duplicate diagnostics (v4.6.16 Task 1/3) --", "Unique desired keys: " + _forestDesiredChunkCount + " | Active: " + _forestTiles.Count + " | Pending: " + _forestAddQueue.Count + " | In-progress: " + _forestActiveResumableJobs + " | Awaiting upload: 0 (upload follows full candidate completion) | Cached: " + _forestTileCache.Count, "Duplicate keys detected (cumulative): " + _forestDuplicateJobsDetected + " | Retained pending (last movement sync): " + _forestRetainedPendingLastSync + " | Retained active (last movement sync): " + _forestRetainedActiveLastSync + " | In-progress resumable build: " + _forestActiveResumableJobs, "TryGetForestTileWorkState(anchor tile): " + state, "-- Terrain incremental retention (v4.6.16 Task 4) --", "Terrain active tiles: " + _terrainTiles.Count + " | Terrain pending queue: " + _terrainQueue.Count + " | " + _lastQueueBudgetStatus, "-- Fast-movement coalescing (v4.6.16 Task 5) --", "Min sync interval: " + EffectiveMinimumMovementSyncIntervalSeconds().ToString("F2", CultureInfo.InvariantCulture) + "s | Fast-movement bypass distance: " + Mathf.RoundToInt((_fastMovementRebuildDistance != null) ? _fastMovementRebuildDistance.Value : 256f) + "m | Seconds since last movement sync: " + (Time.unscaledTime - _lastMovementSyncRealtime).ToString("F2", CultureInfo.InvariantCulture), "-- FOREST GENERATION PERFORMANCE --", "CPU budget/used: " + _forestCurrentCpuBudgetMs.ToString("F2", CultureInfo.InvariantCulture) + "/" + _forestGenerationTimeThisFrameMs.ToString("F2", CultureInfo.InvariantCulture) + "ms | Pressure mode: " + (_forestGenerationPressureMode ? "YES" : "no") + " | frame pressure/teleport: " + (_forestFrameTimePressure ? "yes" : "no") + "/" + (_forestTeleportPressureThisFrame ? "yes" : "no"), "Candidate evaluations: " + _forestCandidatesProcessedThisFrame + " | terrain samples: " + _forestTerrainSamplesThisFrame + " | footprint checks: " + _forestFootprintChecksThisFrame + " | slope checks: " + _forestSlopeChecksThisFrame, "Mesh cards appended: " + _forestMeshCardsAppendedThisFrame + " | uploads: " + _forestMeshesUploadedThisFrame + " (max 1) | activations: " + _forestChunkActivationsThisFrame + " (max 1) | tile commits: " + _forestCompletedTileCommitsThisFrame, "Longest candidate/grounding/mesh/upload slice: " + _forestLongestCandidateBatchMs.ToString("F2", CultureInfo.InvariantCulture) + "/" + _forestLongestGroundingSliceMs.ToString("F2", CultureInfo.InvariantCulture) + "/" + _forestLongestMeshBatchMs.ToString("F2", CultureInfo.InvariantCulture) + "/" + _forestLongestMeshUploadMs.ToString("F2", CultureInfo.InvariantCulture) + "ms", "Admitted generation/audit jobs: " + _forestActiveResumableJobs + "/" + _activeCoverageAuditJobs.Count + " | lightweight queued keys: " + (_forestAddQueue.Count + _coverageSectorLightweightQueue.Count) + " | retained/cancelled/restarted: " + (_forestRetainedActiveLastSync + _forestRetainedPendingLastSync + _coverageAuditJobsRetained) + "/" + (_forestCancelledGenerationJobs + _coverageAuditJobsCancelled) + "/" + (_forestJobsRestartedUnexpectedly + _coverageAuditJobsUnexpectedlyRestarted), "Pooled-buffer allocations forest/coverage: " + _forestPooledBufferAllocations + "/" + _coveragePooledBufferAllocations + " | estimated managed allocation growth this second: " + _forestGcAllocationsThisSecond + " bytes", "-- FOREST COVERAGE --", "Active sectors H/N/M/F/Hor: " + _activeCoverageSectorsByRing[0] + "/" + _activeCoverageSectorsByRing[1] + "/" + _activeCoverageSectorsByRing[2] + "/" + _activeCoverageSectorsByRing[3] + "/" + _activeCoverageSectorsByRing[4] + " | queued lightweight sectors: " + _coverageSectorLightweightQueue.Count, "Audited/remaining/uncovered valid-land cells: " + num5 + "/" + num6 + "/" + num7 + " | unresolved gaps observed: " + _coverageUnresolvedGapCells, "Repair jobs queued: " + _coverageRepairQueue.Count + " | repair cards accepted: " + _coverageRepairCardsAccepted + " | coastal searches active: " + num8 + " | coastal recoveries accepted: " + _coverageCoastalRecoveriesAccepted, "Maximum accepted-card gap H/N/M/F/Hor: " + _ringLargestObservedCoverageGap[0].ToString("F0", CultureInfo.InvariantCulture) + "/" + _ringLargestObservedCoverageGap[1].ToString("F0", CultureInfo.InvariantCulture) + "/" + _ringLargestObservedCoverageGap[2].ToString("F0", CultureInfo.InvariantCulture) + "/" + _ringLargestObservedCoverageGap[3].ToString("F0", CultureInfo.InvariantCulture) + "/" + _ringLargestObservedCoverageGap[4].ToString("F0", CultureInfo.InvariantCulture) + "m | limits 18/22/30/42/60m", "Scheduler/coverage/mesh/diagnostic versions: " + 13 + "/" + 2 + "/" + 1 + "/" + 4 }; for (int k = 0; k < array.Length; k++) { GUI.Label(new Rect(num + 12f, num2 + 22f + (float)k * 20f, 1356f, 20f), array[k], _overlayStyle); } } private bool ComputeSwampGroundingStatus(out float nearestSwampDistance, out string nearestSwampKey) { nearestSwampDistance = float.MaxValue; nearestSwampKey = "none visible"; bool result = _swampMeshCoordinateViolations == 0; foreach (ForestTile value in _forestTiles.Values) { for (int i = 0; i < value.Chunks.Count; i++) { ForestChunk forestChunk = value.Chunks[i]; if (!((Object)(object)forestChunk.SwampBiomeMesh == (Object)null) && forestChunk.Enabled) { float num = FlatDistance(_buildAnchor.x, _buildAnchor.z, forestChunk.Center.x, forestChunk.Center.z); if (num < nearestSwampDistance) { nearestSwampDistance = num; nearestSwampKey = ((Object)forestChunk.Root).name; } } } } return result; } private void DrawSwampGroundingPanel() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_04fb: Unknown result type (might be due to invalid IL or missing references) float num = 12f; float num2 = 12f; GUI.Box(new Rect(num, num2, 1380f, 500f), "New Horizons Treelines v4.6.31 -- Swamp Grounding Diagnostics (page 4/10)"); float nearestSwampDistance; string nearestSwampKey; bool flag = ComputeSwampGroundingStatus(out nearestSwampDistance, out nearestSwampKey) && _groundTransformOk && (_enableStrictFinalHeightmapValidation == null || _enableStrictFinalHeightmapValidation.Value) && (_requireFinalSwampPositionRemainsSwamp == null || _requireFinalSwampPositionRemainsSwamp.Value); string[] array = new string[13] { "Swamp card category nearest: " + ((nearestSwampDistance < float.MaxValue) ? (nearestSwampKey + " at " + Mathf.RoundToInt(nearestSwampDistance) + "m") : "none currently visible"), "Swamp dedicated atlas loaded: " + (((Object)(object)_swampBiomeCardMaterial != (Object)null) ? "YES" : "no") + " | Mixed fallback active: " + (((Object)(object)_swampBiomeCardMaterial == (Object)null && (Object)(object)_treeCardMaterial != (Object)null) ? "YES" : "no") + " | Debug colours: " + ((_debugSwampCardTypeColours != null && _debugSwampCardTypeColours.Value) ? "ON (magenta = dedicated swamp bucket)" : "off"), "Swamp chunks freshly built: " + _swampChunksFreshlyBuilt + " | Cache-restored: " + _swampChunksRestoredFromCache + " | Pool-reused: " + _swampChunksPoolReused + " (cache restore and pool reuse are the same mechanism in this build -- see notes)", "Swamp tree cards emitted: " + _closeSwampEmitted + " | Canopy/proxy emitted: tracked via Accepted " + _swampAccepted + " (category not separately counted -- see notes) | Proxy masses: " + ((_enableProxyMassesInSwamp != null && _enableProxyMassesInSwamp.Value) ? "ENABLED" : "disabled (default)"), "Rejected over ocean/open water (edge check): " + _swampRejectedOceanEdge + " | Rejected shallow-water depth: " + _swampRejectedWater + " | Rejected excessive span (width clamp engaged): " + _swampRejectedExcessiveSpan, "Rejected unsupported root: " + _swampRejectedRootAnchor + " | Rejected unsupported footprint: " + _swampRejectedVisibleLandRatio + " | Rejected final floating (centre + edge checks): " + _swampRejectedFinalFloating, "Swamp mesh coordinate violations: " + _swampMeshCoordinateViolations + " | Maximum world/local coordinate error: " + _swampMaxCoordinateErrorMeters.ToString("F3", CultureInfo.InvariantCulture) + "m", "Maximum final terrain clearance allowed: " + Mathf.Min((_maxFinalGroundFloatingError != null) ? _maxFinalGroundFloatingError.Value : 0.2f, (_swampMaxFinalFloatingClearance != null) ? _swampMaxFinalFloatingClearance.Value : 0.2f).ToString("F2", CultureInfo.InvariantCulture) + "m | Shared final root embed: " + ((_finalRootEmbedDepth != null) ? _finalRootEmbedDepth.Value.ToString("F2", CultureInfo.InvariantCulture) : "0.10") + "m | Legacy swamp embed ignored: " + ((_swampFinalRootEmbedDepth != null) ? _swampFinalRootEmbedDepth.Value.ToString("F2", CultureInfo.InvariantCulture) : "0.00") + "m", "Max canopy card width: " + ((_swampMaxCanopyCardWidth != null) ? _swampMaxCanopyCardWidth.Value.ToString("F0", CultureInfo.InvariantCulture) : "?") + "m | Max proxy card width: " + ((_swampMaxProxyCardWidth != null) ? _swampMaxProxyCardWidth.Value.ToString("F0", CultureInfo.InvariantCulture) : "?") + "m | Footprint radius scale: " + _swampFootprintRadiusScale.Value.ToString("F2", CultureInfo.InvariantCulture), "Cache transform mismatches: " + _swampCacheTransformMismatches + " | Pool reset failures: " + _swampPoolResetFailures, "Nearest floating-card chunk key (last detected): " + _lastSwampFloatingChunkKey, "Dominant current swamp failure: " + DominantSwampRejectionReason(), flag ? "SWAMP PLACEMENT OK" : "SWAMP PLACEMENT VIOLATION" }; for (int i = 0; i < array.Length; i++) { GUI.Label(new Rect(num + 12f, num2 + 22f + (float)i * 20f, 1356f, 20f), array[i], _overlayStyle); } } private void DrawRealClearSkiesPanel() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_082d: Unknown result type (might be due to invalid IL or missing references) float num = 12f; float num2 = 12f; GUI.Box(new Rect(num, num2, 1380f, 520f), "New Horizons Treelines v4.6.31 -- Real Clear Skies Diagnostics (page 5/10)"); bool flag = _enableRealClearSkies != null && _enableRealClearSkies.Value; ClearSkiesOperatingMode clearSkiesOperatingMode = ((_clearSkiesOperatingMode != null) ? _clearSkiesOperatingMode.Value : ClearSkiesOperatingMode.NaturalWeatherAndOccasionalEvent); float num3 = ((Mathf.Abs(_clearSkyTargetBlend) < 0.0001f && Mathf.Abs(_clearSkyCurrentBlend) < 0.0001f) ? 1f : Mathf.Clamp01(1f - Mathf.Abs(_clearSkyTargetBlend - _clearSkyCurrentBlend) / Mathf.Max(0.0001f, Mathf.Abs(_clearSkyTargetBlend) + 0.0001f))); float num4 = ((_lastClearSkyEnvironmentChangeRealtime >= 0f) ? (Time.realtimeSinceStartup - _lastClearSkyEnvironmentChangeRealtime) : (-1f)); string text = ((!flag) ? "CLEAR SKIES INACTIVE (feature disabled, legacy [Atmosphere] haze active)" : ((clearSkiesOperatingMode == ClearSkiesOperatingMode.Disabled) ? "CLEAR SKIES INACTIVE (Operating Mode = Disabled)" : ((_clearSkyTier == ClearSkyWeatherTier.Bad || _clearSkyTier == ClearSkyWeatherTier.SpecialBiome) ? ("CLEAR SKIES INACTIVE-WEATHER-NOT-ELIGIBLE (" + _clearSkyPreservationReason + ")") : (_clearSkyRestoreOk ? ("CLEAR SKIES ACTIVE (" + (_crystalClearEventActive ? "Crystal Clear event profile" : "ordinary clear/light profile") + ", blend " + _clearSkyCurrentBlend.ToString("F2", CultureInfo.InvariantCulture) + ")") : "CLEAR SKIES OVERRIDDEN (restore check failed -- see CLEAR SKY RESTORE below)")))); string[] array = new string[20] { "Real Clear Skies enabled: " + (flag ? "YES" : "no (legacy [Atmosphere] haze system active instead)") + " | Operating mode: " + clearSkiesOperatingMode, "Current environment name: " + _weatherName + " | Current biome: " + (string.IsNullOrEmpty(_clearSkyBiomeName) ? "unknown (GetCurrentBiome unavailable or no local player)" : _clearSkyBiomeName), "Weather classification: " + _weatherClassification + " -> tier " + _clearSkyTier.ToString() + " | Preservation rule active: " + _clearSkyPreservationReason, "-- Crystal Clear occasional event --", "Allow occasional Crystal Clear: " + ((_allowOccasionalCrystalClearWeather != null && _allowOccasionalCrystalClearWeather.Value) ? "YES" : "no") + " | Chance per clear day: " + ((_crystalClearChancePerClearDay != null) ? ((_crystalClearChancePerClearDay.Value * 100f).ToString("F0", CultureInfo.InvariantCulture) + "%") : "?") + " | Duration range: " + ((_crystalClearMinimumDurationMinutes != null) ? _crystalClearMinimumDurationMinutes.Value.ToString("F0", CultureInfo.InvariantCulture) : "?") + "-" + ((_crystalClearMaximumDurationMinutes != null) ? _crystalClearMaximumDurationMinutes.Value.ToString("F0", CultureInfo.InvariantCulture) : "?") + " min", "Event state: " + (_crystalClearEventActive ? ("ACTIVE, " + (_crystalClearEventRemainingSecondsForDiagnostics / 60f).ToString("F1", CultureInfo.InvariantCulture) + " min remaining") : "not active") + " | Last day scheduling was evaluated: " + ((_crystalClearScheduledForDay == int.MinValue) ? "never" : _crystalClearScheduledForDay.ToString(CultureInfo.InvariantCulture)), "Crystal Clear multipliers (event only): fog " + ((_crystalClearFogMultiplier != null) ? _crystalClearFogMultiplier.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | haze " + ((_crystalClearHorizonHazeMultiplier != null) ? _crystalClearHorizonHazeMultiplier.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | tint " + ((_crystalClearDistanceTintMultiplier != null) ? _crystalClearDistanceTintMultiplier.Value.ToString("F2", CultureInfo.InvariantCulture) : "?"), "-- Blend / applied values --", "Clear-sky blend amount: " + _clearSkyCurrentBlend.ToString("F3", CultureInfo.InvariantCulture) + " | Target: " + _clearSkyTargetBlend.ToString("F3", CultureInfo.InvariantCulture) + " | Transition progress: " + (num3 * 100f).ToString("F0", CultureInfo.InvariantCulture) + "%", "Original fog value: " + _savedFogDensity.ToString("F4", CultureInfo.InvariantCulture) + " | Applied fog value: " + _appliedFogDensity.ToString("F4", CultureInfo.InvariantCulture) + " | Fog multiplier: " + _clearSkyAppliedFogMultiplier.ToString("F2", CultureInfo.InvariantCulture), "Cloud control status: " + _cloudControlStatus, "Cloud original alpha (first target): " + _cloudOriginalAlphaForDiagnostics.ToString("F2", CultureInfo.InvariantCulture) + " | Applied opacity multiplier: " + _cloudAppliedOpacityMultiplier.ToString("F2", CultureInfo.InvariantCulture) + " | Target profile: " + (_crystalClearEventActive ? ("Crystal " + ((_crystalClearCloudOpacityMultiplier != null) ? _crystalClearCloudOpacityMultiplier.Value.ToString("F2", CultureInfo.InvariantCulture) : "?")) : ("Clear " + ((_clearWeatherCloudOpacityMultiplier != null) ? _clearWeatherCloudOpacityMultiplier.Value.ToString("F2", CultureInfo.InvariantCulture) : "?"))), "Native horizon-haze value (ClarityWeatherScale): " + ClarityWeatherScale().ToString("F3", CultureInfo.InvariantCulture) + " | New Horizons haze multiplier: " + _clearSkyAppliedHazeMultiplier.ToString("F2", CultureInfo.InvariantCulture), "New Horizons forest-tint multiplier: " + _clearSkyAppliedTintMultiplier.ToString("F2", CultureInfo.InvariantCulture) + " | Far forest darkness (effective): " + FarForestDarkness().ToString("F2", CultureInfo.InvariantCulture) + " | Far terrain darkness (effective): " + FarTerrainDarkness().ToString("F2", CultureInfo.InvariantCulture), "Mistlands preservation active: " + ((_preserveMistlandsMist != null && _preserveMistlandsMist.Value) ? "ON" : "off") + " | Storm preservation active: " + ((_preserveStormWeather != null && _preserveStormWeather.Value) ? "ON" : "off"), "Original values captured: " + (_hazeApplied ? ("YES (fog " + _savedFogDensity.ToString("F4", CultureInfo.InvariantCulture) + ")") : "not currently applied"), "Last environment change: " + ((num4 < 0f) ? "never" : (num4.ToString("F1", CultureInfo.InvariantCulture) + "s ago")), "Last clear-sky exception: " + _lastClearSkyException, text, (_clearSkyRestoreOk && _cloudRestoreOk) ? "CLEAR SKY RESTORE OK (fog + complete cloud property blocks)" : "CLEAR SKY RESTORE VIOLATION" }; for (int i = 0; i < array.Length; i++) { GUI.Label(new Rect(num + 12f, num2 + 22f + (float)i * 20f, 1356f, 20f), array[i], _overlayStyle); } } private void DrawStrictGroundingPanel() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0c65: Unknown result type (might be due to invalid IL or missing references) float num = 12f; float num2 = 12f; GUI.Box(new Rect(num, num2, 1380f, 800f), "New Horizons Treelines v4.6.31 -- Cross-Biome Stacking / Strict Grounding (page 6/10)"); bool flag = _groundTransformOk && (_enableStrictFinalHeightmapValidation == null || _enableStrictFinalHeightmapValidation.Value) && (_rejectGroundCardsOverOpenWater == null || _rejectGroundCardsOverOpenWater.Value) && (_maximumUnsupportedSpan == null || _maximumUnsupportedSpan.Value <= 1.5001f) && (_maxFinalGroundFloatingError == null || _maxFinalGroundFloatingError.Value <= 0.2001f) && (_maxFinalGroundBurialError == null || _maxFinalGroundBurialError.Value <= 0.60010004f); string[] array = new string[41] { "Ground cards considered: " + _groundCardsConsidered + " | Accepted: " + _groundCardsAccepted, "Rejected floating: " + _groundCardsRejectedFloating + " | Rejected burial: " + _groundCardsRejectedBurial + " | Combined final rejects: " + _groundCardsRejectedFloatingOrBurial, "Rejected unsupported root/span: " + _groundCardsRejectedUnsupportedRoot + " | Rejected over open water: " + _groundCardsRejectedOpenWater + " | Rejected height variance: " + _groundCardsRejectedHeightVariance + " | Unsupported footprint: " + _noFloatRejectedVisibleLandRatio, "Cross-biome duplicates suppressed: " + _groundCardsDuplicatesSuppressed + " (Plains: " + _plainsDuplicatesSuppressed + ") | Enable Cross-Biome Duplicate Rejection: " + ((_enableCrossBiomeDuplicateRejection != null && _enableCrossBiomeDuplicateRejection.Value) ? "ON" : "off"), "Mixed/dedicated fallback conflicts: none possible by construction (GetCardBucket routes each candidate into exactly one bucket -- see IMPLEMENTATION_NOTES_v4.5.9.md)", "Boundary/normal chunk duplicate conflicts: none possible by construction (tuple-keyed by (size,x,z), see v4.5.5 audit) | Cache duplicate conflicts: " + _swampCacheTransformMismatches + " (swamp-tracked; see page 4)", "Pool stale-mesh conflicts (reset failures): " + _swampPoolResetFailures, "Nearest/last stacked-card violation: " + _lastStackedCardViolation, "Maximum base-height disagreement (suppressed duplicates): " + _maxBaseHeightDisagreement.ToString("F2", CultureInfo.InvariantCulture) + "m | Warning threshold: " + ((_duplicateBaseHeightDifferenceWarning != null) ? _duplicateBaseHeightDifferenceWarning.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + "m", "Maximum final world/heightmap error observed: " + _maxFinalWorldHeightmapError.ToString("F3", CultureInfo.InvariantCulture) + "m", "-- Plains-specific --", "Plains raw candidates: " + _plainsCandidates + " | Accepted tree cards: " + _plainsAccepted + " (no dedicated Plains atlas exists -- these render via the mixed atlas, see notes)", "Plains duplicates suppressed: " + _plainsDuplicatesSuppressed + " | Rejected ground variance/floating: " + _plainsCardsRejectedGroundError, "Plains maximum final ground error: " + _plainsMaxFinalGroundError.ToString("F3", CultureInfo.InvariantCulture) + "m | Plains stacked-card violations: " + _plainsStackedCardViolations, "Ground transform: " + _groundTransformDetail, "-- Biome routing (Part 8/9) --", "Final-biome resamples: " + _finalBiomeResamples + " | Biome changed after retry: " + _biomeChangedAfterRetry + " | Large cards split on uneven terrain: " + _groundCardsSplitOnUnevenTerrain, "Swamp wrong-biome rejections (final position left swamp): " + _swampWrongBiomeRejections + " | Swamp candidates rejected (no valid ground within inland retry distance): " + _swampCandidatesRejectedNoValidGround, (_swampWrongBiomeRejections == 0L && _groundTransformOk) ? "BIOME ROUTING OK" : "BIOME ROUTING VIOLATION", flag ? "STRICT GROUNDING OK" : "STRICT GROUNDING VIOLATION", "-- Rendered ground source (v4.6.10 Part 1) --", "Rendered ground source (last sample): " + _lastGroundedRenderedSource + " | Far-terrain mesh samples: " + _renderedGroundSourceFarMeshCount + " | Provider fallback (no tile yet): " + _renderedGroundSourceProviderFallbackCount + " | Native heightmap: " + _renderedGroundSourceNativeCount, "Rendered ground Y (last sample): " + _lastRenderedGroundY.ToString("F2", CultureInfo.InvariantCulture) + "m | Final visible-root Y: " + _lastFinalVisibleRootY.ToString("F2", CultureInfo.InvariantCulture) + "m | Final visible-root error: " + _lastFinalVisibleRootError.ToString("F3", CultureInfo.InvariantCulture) + "m (max observed " + _maxFinalVisibleRootErrorObserved.ToString("F3", CultureInfo.InvariantCulture) + "m)", "-- Manual vertical adjustment (v4.6.10 Part 2) --", "Global vertical adjustment: " + ((_treeCardVerticalAdjustment != null) ? _treeCardVerticalAdjustment.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + "m | Last applied (global+biome): " + _lastAppliedVerticalAdjustment.ToString("F2", CultureInfo.InvariantCulture) + "m", "Cards corrected downward: " + _cardsCorrectedDownward + " | Cards rejected after correction: " + _cardsRejectedAfterVerticalCorrection, "-- Mountain card scale (v4.6.24 visible dimensions) --", "Height multiplier: " + ((_mountainTreeHeightMultiplier != null) ? _mountainTreeHeightMultiplier.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Width multiplier: " + ((_mountainTreeWidthMultiplier != null) ? _mountainTreeWidthMultiplier.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Mountain vertical adjustment: " + ((_mountainVerticalAdjustmentFinal != null) ? _mountainVerticalAdjustmentFinal.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + "m", "Average generated height: " + ((_mountainSizeSampleCount > 0) ? (_mountainHeightSampleSum / (double)_mountainSizeSampleCount).ToString("F1", CultureInfo.InvariantCulture) : "n/a") + "m | Average generated width: " + ((_mountainSizeSampleCount > 0) ? (_mountainWidthSampleSum / (double)_mountainSizeSampleCount).ToString("F1", CultureInfo.InvariantCulture) : "n/a") + "m | Width/height ratio: " + ((_mountainSizeSampleCount > 0 && _mountainHeightSampleSum > 0.0) ? (_mountainWidthSampleSum / _mountainHeightSampleSum).ToString("F2", CultureInfo.InvariantCulture) : "n/a") + " (samples " + _mountainSizeSampleCount + ")", "MOUNTAIN CARD DIMENSIONS: " + _mountainCardDimensionSample, "Mountain proportionally reduced on slopes: " + _mountainProportionallyReduced + " | Split on slopes: " + _mountainSplitOnSlopes + " | Minimum automatic scale: " + ((_mountainMinimumAutomaticWidthScale != null) ? _mountainMinimumAutomaticWidthScale.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Visible-width cap: " + ((_maximumMountainGroundCardWidth != null) ? _maximumMountainGroundCardWidth.Value.ToString("F0", CultureInfo.InvariantCulture) : "?") + "m", "-- Full visible-edge slope grounding (v4.6.13 Task 1) --", "Full-edge cards tested: " + _slopeAwareCardsTested + " | Edge floating detected: " + _slopeAwareEdgeFloatingDetected + " | Width reduced: " + _slopeAwareWidthReduced + " | Split accepted: " + _slopeAwareSplitAccepted + " | Rejected after split: " + _slopeAwareRejectedAfterSplit, "Maximum final edge error observed: " + _slopeAwareMaxFinalEdgeError.ToString("F3", CultureInfo.InvariantCulture) + "m | Enable Slope-Aware Card Grounding: " + ((_enableSlopeAwareCardGrounding == null || _enableSlopeAwareCardGrounding.Value) ? "ON" : "off"), "-- Black Forest card geometry (v4.6.17) --", "Crossed-plane cards emitted: " + _blackForestCrossedCardsEmitted + " | Single-plane cards detected: " + _blackForestSinglePlaneCardsDetected + " | Rejected too thin: " + _blackForestRejectedTooThin, "Average final height: " + ((_blackForestFinalCardSamples > 0) ? (_blackForestFinalHeightSum / (double)_blackForestFinalCardSamples).ToString("F1", CultureInfo.InvariantCulture) : "n/a") + "m | Average final crown width: " + ((_blackForestFinalCardSamples > 0) ? (_blackForestFinalWidthSum / (double)_blackForestFinalCardSamples).ToString("F1", CultureInfo.InvariantCulture) : "n/a") + "m | Average final ratio: " + ((_blackForestFinalCardSamples > 0 && _blackForestFinalHeightSum > 0.0) ? (_blackForestFinalWidthSum / _blackForestFinalHeightSum).ToString("F2", CultureInfo.InvariantCulture) : "n/a") + " (samples " + _blackForestFinalCardSamples + ")", "Worst final ratio observed: " + ((_blackForestWorstFinalRatio < float.MaxValue) ? _blackForestWorstFinalRatio.ToString("F2", CultureInfo.InvariantCulture) : "n/a") + " | Configured minimum: " + ((_blackForestMinimumWidthToHeightRatio != null) ? _blackForestMinimumWidthToHeightRatio.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Proportionally reduced on slopes: " + _blackForestProportionallyReduced + " | Split on slopes: " + _blackForestSplitOnSlopes, "Atlas cell selection -- broad: " + _blackForestBroadCellSelections + " | standard: " + _blackForestStandardCellSelections + " | narrow: " + _blackForestNarrowCellSelections, "BLACK FOREST CARD DIMENSIONS: " + _blackForestPineDimensionSample, (_blackForestSinglePlaneCardsDetected == 0L && (_blackForestWorstFinalRatio >= float.MaxValue || _blackForestWorstFinalRatio >= ((_blackForestMinimumWidthToHeightRatio != null) ? (_blackForestMinimumWidthToHeightRatio.Value - 0.01f) : 0.57f)) && _blackForestCrossedCardsEmitted > 0) ? "BLACK FOREST CARD GEOMETRY OK" : ("BLACK FOREST CARD GEOMETRY: " + ((_blackForestCrossedCardsEmitted == 0L) ? "no crossed cards observed yet" : ((_blackForestSinglePlaneCardsDetected > 0) ? (_blackForestSinglePlaneCardsDetected + " single-plane card(s) detected") : "ratio floor violated"))) }; for (int i = 0; i < array.Length; i++) { GUI.Label(new Rect(num + 12f, num2 + 22f + (float)i * 20f, 1356f, 20f), array[i], _overlayStyle); } } private string BuildTrueColourDiagnosticDetail() { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) if (_trueColourDiagnosticTarget == null) { return ""; } switch (_trueColourDiagnosticTarget.Value) { case TrueColourDiagnosticTarget.NativeTerrainMaterial: return " | " + _nativeTerrainDiagnosticStatus + " | Shader/material: live Heightmap renderer shared material | Property: renderer _Color property block | Value before: captured complete property block | Value written: RGBA(1,0.1,0.85,1) | One frame later: held while selected | Overwritten: " + (_nativeTerrainDiagnosticApplied ? "no observed" : "target unavailable") + " | Restore: captured block"; case TrueColourDiagnosticTarget.NewHorizonsFarTerrain: if (!UsesFullResolutionProviderTerrainColour()) { return " | Target found: YES | Shader: Unlit/Texture or Legacy Shaders/Diffuse | Material: per-tile fallback texture (ComputeTerrainDisplayColor) | Property: baked RGB | Value before: provider biome colour | Value written: magenta during diagnostic rebuild | One frame later: static until rebuild | Overwritten: no"; } return " | Target found: YES | Shader: Unlit/Texture or Legacy Shaders/Diffuse | Material: shared full-resolution provider terrain map | UV: global world/provider UV | Property: shared _Color | Value before: live weather/daylight colour | Value written: RGBA(1,0,0.9,1) | One frame later: held by UpdateSharedTerrainMaterialLighting | Overwritten: no"; case TrueColourDiagnosticTarget.NativeFogOutput: return " | Target found: YES | Shader/material: RenderSettings native fog output | Property: fogColor | Value before: " + ColorUtility.ToHtmlStringRGB(_savedFogColour) + " | Value written: RGBA(0,1,0.1,1) | One frame later: " + (_fogColourDiagnosticApplied ? "held green" : "restored") + " | Overwritten: " + (_fogColourDiagnosticOverwritten ? "YES (late native/environment write observed before reapply)" : "no") + " | Restore: captured fog colour"; case TrueColourDiagnosticTarget.NewHorizonsTerrainTint: return " | Target found: YES | Shader/material: New Horizons far-terrain tile texture | Stage: terrain-tint output | Value before: provider colour + forest tint | Value written: yellow where tint amount > 0 | One frame later: baked until rebuild | Overwritten: no"; case TrueColourDiagnosticTarget.NewHorizonsHaze: return " | Target found: " + ((_enableHorizonClarity.Value && _reduceHorizonHaze.Value) ? "YES" : "NO (horizon clarity/haze disabled)") + " | Stage: New Horizons clarity/haze output | Value written: violet | One frame later: baked until rebuild | Overwritten: no"; case TrueColourDiagnosticTarget.ForestTerrainTint: return " | Target found: YES | Shader/material: New Horizons far-terrain tile texture | Stage: forest-density tint mask | Value written: orange where forest mask > 0 | One frame later: baked until rebuild | Overwritten: no"; case TrueColourDiagnosticTarget.NewHorizonsTreeCardMaterials: return " | Target found: " + (((Object)(object)_treeCardMaterial != (Object)null) ? "YES" : "NO (atlas material unavailable)") + " | Shader/material: shared tree/canopy/mountain/swamp atlas materials | Property: _Color | Value before: fresh shared RGB-lighting result | Value written: RGBA(0,0.9,1,a) | One frame later: held by continuous shared update | Overwritten: no"; default: return ""; } } private string CurrentLightingPeriodName() { float lastAmbientLuminanceForDiagnostics = _lastAmbientLuminanceForDiagnostics; bool flag = _weatherClassification == "light"; if (_weatherClassification == "blocked") { return "Storm"; } if (lastAmbientLuminanceForDiagnostics < 0.1f) { return "Night"; } if (lastAmbientLuminanceForDiagnostics < 0.25f) { if (!flag) { return "Night"; } return "Overcast Night"; } if (lastAmbientLuminanceForDiagnostics < 0.5f) { if (!flag) { return "Twilight"; } return "Overcast"; } if (lastAmbientLuminanceForDiagnostics < 0.75f) { if (!flag) { return "Sunset"; } return "Overcast"; } if (lastAmbientLuminanceForDiagnostics < 0.9f) { return "Late Afternoon"; } return "Bright Day"; } private void DrawTrueColourDistantLandPanel() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_0b09: Unknown result type (might be due to invalid IL or missing references) float num = 12f; float num2 = 12f; GUI.Box(new Rect(num, num2, 1380f, 620f), "New Horizons Treelines v4.6.31 -- Continuous Terrain Colour Diagnostics (page 7/10)"); bool flag = _enableTrueColourDistantLand != null && _enableTrueColourDistantLand.Value; float num3 = ComputeTrueColourAmount(); float clearSkyAppliedFogMultiplier = _clearSkyAppliedFogMultiplier; float clearSkyAppliedHazeMultiplier = _clearSkyAppliedHazeMultiplier; float clearSkyAppliedTintMultiplier = _clearSkyAppliedTintMultiplier; string[] array = new string[29] { "Enable Original Distant Land Colour: " + (flag ? "YES" : "no") + " | Current true-colour amount: " + num3.ToString("F2", CultureInfo.InvariantCulture), "Weather classification: " + _weatherClassification + " | Current biome: " + (string.IsNullOrEmpty(_clearSkyBiomeName) ? "unknown" : _clearSkyBiomeName), "Provider strength: " + ((_clearWeatherOriginalTerrainColourStrength != null) ? _clearWeatherOriginalTerrainColourStrength.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Clear-day atmosphere: " + ((_clearWeatherAtmosphericColourStrength != null) ? _clearWeatherAtmosphericColourStrength.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Brightness loss: " + ((_clearWeatherMaximumTerrainDarkening != null) ? _clearWeatherMaximumTerrainDarkening.Value.ToString("F2", CultureInfo.InvariantCulture) : "?"), "Saturation loss: " + ((_clearWeatherDistantSaturationStrength != null) ? _clearWeatherDistantSaturationStrength.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Radial safety width: " + ((_radialTerrainColourTransitionWidth != null) ? _radialTerrainColourTransitionWidth.Value.ToString("F0", CultureInfo.InvariantCulture) : "?") + "m", "Provider RGB: " + FormatTerrainColour(_terrainColourDiagnosticProvider) + " | Provider colour space: " + _terrainColourProviderSpace, "Near final RGB: " + FormatTerrainColour(_terrainColourDiagnosticNear) + " ratio " + _terrainColourDiagnosticNearRatio.ToString("F3", CultureInfo.InvariantCulture) + " | Far final RGB: " + FormatTerrainColour(_terrainColourDiagnosticFar) + " ratio " + _terrainColourDiagnosticFarRatio.ToString("F3", CultureInfo.InvariantCulture), "Horizon final RGB: " + FormatTerrainColour(_terrainColourDiagnosticHorizon) + " ratio " + _terrainColourDiagnosticHorizonRatio.ToString("F3", CultureInfo.InvariantCulture) + " | Post-correction darkening: " + (_terrainColourPostCorrectionDarkening ? "YES" : "no") + " | Radial-distance multiplier active: " + (_terrainColourRadialMultiplierActive ? "YES" : "no"), "-- Probable distance-darkening sources (this build) --", "Native Valheim fog/ambient: NOT modified by New Horizons' own far-terrain tint mesh (RenderSettings.fogDensity is a separate, camera-wide effect -- see Real Clear Skies, page 5)", "Terrain colour path: " + (UsesFullResolutionProviderTerrainColour() ? "FULL-RESOLUTION PROVIDER MAP (global UV)" : "per-tile baked fallback") + " | full-res tiles " + _fullResolutionTerrainTilesBuilt + " | shared material RGB " + _lastSharedTerrainMaterialColour.r.ToString("F2", CultureInfo.InvariantCulture) + "," + _lastSharedTerrainMaterialColour.g.ToString("F2", CultureInfo.InvariantCulture) + "," + _lastSharedTerrainMaterialColour.b.ToString("F2", CultureInfo.InvariantCulture), "New Horizons far-terrain tint strength: " + ForestTerrainTintStrength().ToString("F2", CultureInfo.InvariantCulture) + " | distance tint strength: " + DistanceTintStrength().ToString("F2", CultureInfo.InvariantCulture) + " | fallback colour resolution " + ((_fallbackTerrainColourTextureResolution != null) ? _fallbackTerrainColourTextureResolution.Value.ToString(CultureInfo.InvariantCulture) : "64"), "New Horizons horizon-clarity contrast/darkness (pre-True-Colour): terrain " + FarTerrainContrast().ToString("F2", CultureInfo.InvariantCulture) + "/" + FarTerrainDarkness().ToString("F2", CultureInfo.InvariantCulture) + " | forest " + FarForestContrast().ToString("F2", CultureInfo.InvariantCulture) + "/" + FarForestDarkness().ToString("F2", CultureInfo.InvariantCulture), "Final clear-sky blend (Real Clear Skies, shared driver when enabled): " + _clearSkyCurrentBlend.ToString("F2", CultureInfo.InvariantCulture), "Identified ring source: " + VisualExclusionRadius().ToString("F0", CultureInfo.InvariantCulture) + "m native/New Horizons material handoff plus removed procedural provider fade formerly beginning at 1200m", "Native fog multiplier (Real Clear Skies): " + clearSkyAppliedFogMultiplier.ToString("F2", CultureInfo.InvariantCulture) + " | New Horizons haze multiplier: " + clearSkyAppliedHazeMultiplier.ToString("F2", CultureInfo.InvariantCulture) + " | New Horizons forest-tint multiplier: " + clearSkyAppliedTintMultiplier.ToString("F2", CultureInfo.InvariantCulture), "Preserve Storm/Special Biome Atmosphere: " + ((_preserveStormTerrainAtmosphere != null && _preserveStormTerrainAtmosphere.Value) ? "ON" : "off") + " / " + ((_preserveSpecialBiomeAtmosphereTerrain != null && _preserveSpecialBiomeAtmosphereTerrain.Value) ? "ON" : "off"), "Terrain-colour tier key: " + (_lastTrueColourTierKey ?? "n/a") + " | Pending terrain-colour rebuild: " + ((_pendingTerrainColourRebuildDebounce > 0f) ? (_pendingTerrainColourRebuildDebounce.ToString("F1", CultureInfo.InvariantCulture) + "s") : "none"), "-- True Colour diagnostic target test (Part 'prove the true-colour target') --", "True Colour Diagnostic Target: " + ((_trueColourDiagnosticTarget != null) ? _trueColourDiagnosticTarget.Value.ToString() : "Off") + BuildTrueColourDiagnosticDetail(), "TRUE COLOUR APPLY: " + ((_trueColourDiagnosticTarget != null && _trueColourDiagnosticTarget.Value != TrueColourDiagnosticTarget.Off) ? "OVERRIDDEN (diagnostic tint active -- do not ship)" : ((!flag) ? "TARGET NOT FOUND (feature disabled)" : (UsesFullResolutionProviderTerrainColour() ? "OK (full-resolution provider map + live shared weather/daylight colour)" : ((num3 > 0.01f) ? ("OK (blend " + num3.ToString("F2", CultureInfo.InvariantCulture) + " baked into fallback terrain textures)") : "OK (0 blend -- not clear weather right now)")))), "-- Range (preset/E, see also page 3) --", "Active preset: " + _qualityPreset.Value.ToString() + " | Extension E: " + Mathf.RoundToInt(ExtensionDistance()) + "m | Final outer boundary: " + Mathf.RoundToInt(FinalForestRange()) + "m | Range clamp reason: " + RangeClampReason(), "-- Daylight lighting (Part 16/17, expanded stages) --", "Ambient luminance: " + _lastAmbientLuminanceForDiagnostics.ToString("F2", CultureInfo.InvariantCulture) + " | Lighting period: " + CurrentLightingPeriodName() + " | Tree brightness multiplier: " + _lastTreeBrightnessForDiagnostics.ToString("F2", CultureInfo.InvariantCulture) + " | Natural Daylight Darkening: " + ((_naturalDaylightDarkening != null && _naturalDaylightDarkening.Value) ? "ON" : "off"), "Biome Colour Preservation: " + ((_biomeColourPreservation != null) ? _biomeColourPreservation.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Weather Colour Influence: " + ((_weatherColourInfluence != null) ? _weatherColourInfluence.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Minimum Tree Luminance: " + ((_minimumTreeLuminance != null) ? _minimumTreeLuminance.Value.ToString("F2", CultureInfo.InvariantCulture) : "?"), "Distance zone gradient: Zone2 (mid) " + ((_midDistanceOriginalColourStrength != null) ? _midDistanceOriginalColourStrength.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Zone3 (far/horizon) " + ((_farDistanceOriginalColourStrength != null) ? _farDistanceOriginalColourStrength.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " atmospheric " + ((_farDistanceAtmosphericInfluence != null) ? _farDistanceAtmosphericInfluence.Value.ToString("F2", CultureInfo.InvariantCulture) : "?"), "-- Near-handoff tree colour (Zone 1) --", "Preserve Original Colour Near Handoff: " + ((_preserveOriginalColourNearHandoff != null && _preserveOriginalColourNearHandoff.Value) ? "ON" : "off") + " | Applied Zone 1 (all chunk sizes): H to H+" + Mathf.RoundToInt((_nearHandoffColourBandWidth != null) ? _nearHandoffColourBandWidth.Value : 800f) + "m (distance-gated all chunk sizes) | Chunks tinted this pass: " + _nearHandoffChunksTinted, "Near-handoff brightness (daylight-preserved): " + _lastNearHandoffBrightnessForDiagnostics.ToString("F2", CultureInfo.InvariantCulture) + " | Original colour strength: " + ((_nearHandoffDaylightOriginalColourStrength != null) ? _nearHandoffDaylightOriginalColourStrength.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Weather influence: " + ((_nearHandoffWeatherColourInfluence != null) ? _nearHandoffWeatherColourInfluence.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") }; for (int i = 0; i < array.Length; i++) { GUI.Label(new Rect(num + 12f, num2 + 22f + (float)i * 20f, 1356f, 20f), array[i], _overlayStyle); } } private void DrawTreeLightingPanel() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0577: Unknown result type (might be due to invalid IL or missing references) float num = 12f; float num2 = 12f; GUI.Box(new Rect(num, num2, 1380f, 400f), "New Horizons Treelines v4.6.31 -- Continuous Tree Lighting Diagnostics (page 8/10)"); int num3 = 0; if ((Object)(object)_treeCardMaterial != (Object)null) { num3++; } if ((Object)(object)_canopyCardMaterial != (Object)null) { num3++; } if ((Object)(object)_mountainBiomeCardMaterial != (Object)null) { num3++; } if ((Object)(object)_swampBiomeCardMaterial != (Object)null) { num3++; } string text = ((_trueColourDiagnosticTarget != null && _trueColourDiagnosticTarget.Value == TrueColourDiagnosticTarget.NewHorizonsTreeCardMaterials) ? "TREE LIGHTING APPLY OVERRIDDEN (tree-card diagnostic tint selected)" : ((num3 > 0) ? "TREE LIGHTING APPLY OK" : "TREE LIGHTING APPLY OVERRIDDEN (no shared card material loaded yet)")); float num4 = ((_lastTreeLightingApplyRealtime >= 0f) ? (Time.realtimeSinceStartup - _lastTreeLightingApplyRealtime) : (-1f)); string[] array = new string[9] { "Natural Daylight Darkening: " + ((_naturalDaylightDarkening != null && _naturalDaylightDarkening.Value) ? "ON" : "off") + " | Transition: " + ((_lightingTransitionSeconds != null) ? _lightingTransitionSeconds.Value.ToString("F1", CultureInfo.InvariantCulture) : "5.0") + "s", "Sun elevation: " + _lastSunElevationForDiagnostics.ToString("F1", CultureInfo.InvariantCulture) + " deg | Daylight factor: " + _lastDaylightFactorForDiagnostics.ToString("F2", CultureInfo.InvariantCulture) + " | Period: " + CurrentLightingPeriodName(), "Ambient luminance: " + _lastAmbientLuminanceForDiagnostics.ToString("F2", CultureInfo.InvariantCulture) + " | Current smoothed brightness: " + _lastTreeBrightnessForDiagnostics.ToString("F2", CultureInfo.InvariantCulture), "Weather: " + _weatherClassification + " (" + _weatherName + ") | Global weather influence: " + ((_weatherColourInfluence != null) ? _weatherColourInfluence.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Near-H weather influence: " + ((_nearHandoffWeatherColourInfluence != null) ? _nearHandoffWeatherColourInfluence.Value.ToString("F2", CultureInfo.InvariantCulture) : "?"), "Near-H original-colour strength: " + ((_nearHandoffDaylightOriginalColourStrength != null) ? _nearHandoffDaylightOriginalColourStrength.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Fog influence: " + ((_nearHandoffFogColourInfluence != null) ? _nearHandoffFogColourInfluence.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + " | Current Zone 1 brightness: " + _lastNearHandoffBrightnessForDiagnostics.ToString("F2", CultureInfo.InvariantCulture), "Zone 1 range: H=" + NativeTreelineHandoff().ToString("F0", CultureInfo.InvariantCulture) + "m through H+" + ((_nearHandoffColourBandWidth != null) ? _nearHandoffColourBandWidth.Value.ToString("F0", CultureInfo.InvariantCulture) : "800") + "m | All-size tinted chunks: " + _nearHandoffChunksTinted, "Material baseline status: " + num3 + "/4 shared atlas materials available | Last shared update: " + ((num4 >= 0f) ? (num4.ToString("F2", CultureInfo.InvariantCulture) + "s ago") : "not yet"), "Brightness endpoints Night/Moon/Twilight/Sunset/Late/Day: " + ((_nightTreeBrightness != null) ? _nightTreeBrightness.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + "/" + ((_moonlitNightTreeBrightness != null) ? _moonlitNightTreeBrightness.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + "/" + ((_twilightTreeBrightness != null) ? _twilightTreeBrightness.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + "/" + ((_sunsetTreeBrightness != null) ? _sunsetTreeBrightness.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + "/" + ((_lateAfternoonTreeBrightness != null) ? _lateAfternoonTreeBrightness.Value.ToString("F2", CultureInfo.InvariantCulture) : "?") + "/" + ((_daylightTreeBrightness != null) ? _daylightTreeBrightness.Value.ToString("F2", CultureInfo.InvariantCulture) : "?"), text }; for (int i = 0; i < array.Length; i++) { GUI.Label(new Rect(num + 12f, num2 + 22f + (float)i * 20f, 1356f, 20f), array[i], _overlayStyle); } } private void DrawHandoffFillPanel() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0706: Unknown result type (might be due to invalid IL or missing references) float num = 12f; float num2 = 12f; GUI.Box(new Rect(num, num2, 1380f, 440f), "New Horizons Treelines v4.6.31 -- Exact Handoff Trace / Guaranteed Fill (page 9/10)"); NativeTreelineMode nativeTreelineMode = ((_nativeTreelineMode != null) ? _nativeTreelineMode.Value : NativeTreelineMode.AutoDetect); float num3 = NativeTreelineHandoff(); float num4 = EffectiveTreeCardStart(); float nearestEnabledForestChunkEdge = _nearestEnabledForestChunkEdge; float num5 = ((nearestEnabledForestChunkEdge < float.MaxValue) ? (nearestEnabledForestChunkEdge - num3) : float.NaN); float num6 = ((_nativeTreelineSeamTolerance != null) ? _nativeTreelineSeamTolerance.Value : 4f); bool flag = num4 >= 499.5f && num3 < 499.5f; string text = nativeTreelineMode switch { NativeTreelineMode.AutoDetect => "dedicated native tree-distance detection", NativeTreelineMode.ManualCalibrated => "Manual calibrated H", _ => "configured default fallback", }; string text2 = "none observed within the current trace window (2s) -- either the seam is fully covered, or no candidate has been evaluated that close yet"; float num7 = float.MaxValue; if (_traceNearestExclusionRejectedDistance < num7 && _traceNearestExclusionRejectedDistance < _traceNearestAcceptedCardDistance) { num7 = _traceNearestExclusionRejectedDistance; text2 = "candidate-stage forest exclusion margin (OutsideForestExclusion) at " + _traceNearestExclusionRejectedDistance.ToString("F1", CultureInfo.InvariantCulture) + "m"; } if (_traceNearestGroundingRejectedDistance < num7 && _traceNearestGroundingRejectedDistance < _traceNearestAcceptedCardDistance) { num7 = _traceNearestGroundingRejectedDistance; text2 = "strict grounding/water/slope validation at " + _traceNearestGroundingRejectedDistance.ToString("F1", CultureInfo.InvariantCulture) + "m"; } if (_traceNearestBiomeRejectedDistance < num7 && _traceNearestBiomeRejectedDistance < _traceNearestAcceptedCardDistance) { num7 = _traceNearestBiomeRejectedDistance; text2 = "final-biome routing (e.g. swamp candidate resampled off swamp) at " + _traceNearestBiomeRejectedDistance.ToString("F1", CultureInfo.InvariantCulture) + "m"; } if (nearestEnabledForestChunkEdge < float.MaxValue && _traceNearestAcceptedCardDistance < float.MaxValue && nearestEnabledForestChunkEdge - _traceNearestAcceptedCardDistance > num6) { text2 = "runtime chunk visibility bounds (card accepted at " + _traceNearestAcceptedCardDistance.ToString("F1", CultureInfo.InvariantCulture) + "m, but nearest enabled renderer edge is " + nearestEnabledForestChunkEdge.ToString("F1", CultureInfo.InvariantCulture) + "m)"; } string text3 = (float.IsNaN(num5) ? "STRICT 215M HANDOFF: NOT MEASURED (no enabled card edge currently visible)" : ((num5 < -0.05f) ? ("STRICT 215M HANDOFF: VIOLATION (nearest edge " + (0f - num5).ToString("F1", CultureInfo.InvariantCulture) + "m inside H)") : ((!(num5 <= num6) || !HandoffFillCoverageStatus().StartsWith("HANDOFF COVERAGE OK")) ? ("STRICT 215M HANDOFF: GAP (" + num5.ToString("F1", CultureInfo.InvariantCulture) + "m beyond seam tolerance, or fill band below target)") : "STRICT 215M HANDOFF OK"))); string[] array = new string[19] { "Native Treeline Mode: " + nativeTreelineMode.ToString() + " | Manual calibrated H (raw, ManualCalibrated only): " + ((nativeTreelineMode == NativeTreelineMode.ManualCalibrated) ? (Mathf.RoundToInt(RawNativeTreelineRadius()) + "m") : "n/a (mode is not ManualCalibrated)"), "Effective H (after handoff offset): " + Mathf.RoundToInt(num3) + "m | Effective inner boundary (H - O): " + Mathf.RoundToInt(num4) + "m", "Preset override of H: none (presets only ever set Extension Distance E -- see Part 14/15, unchanged this pass) | Fallback ignored: " + ((nativeTreelineMode == NativeTreelineMode.ManualCalibrated) ? "yes (DefaultFallback/AutoDetect values are not consulted while ManualCalibrated is active)" : "n/a") + " | Preset cannot override H: yes", "-- Numeric handoff trace (nearest distance from build anchor, metres, rolling 2s window) --", "Closest desired fixed forest cell (H itself): " + Mathf.RoundToInt(num3) + "m", "Closest raw candidate (passed density+slope): " + FormatTraceDistance(_traceNearestRawCandidateDistance), "Closest candidate rejected by exclusion margin: " + FormatTraceDistance(_traceNearestExclusionRejectedDistance), "Closest candidate rejected by grounding/water/slope: " + FormatTraceDistance(_traceNearestGroundingRejectedDistance), "Closest candidate rejected by final-biome routing: " + FormatTraceDistance(_traceNearestBiomeRejectedDistance), "Closest accepted/emitted card: " + FormatTraceDistance(_traceNearestAcceptedCardDistance), "Nearest enabled renderer-bounds edge (live, not windowed): " + ((nearestEnabledForestChunkEdge < float.MaxValue) ? (Mathf.RoundToInt(nearestEnabledForestChunkEdge) + "m") : "none visible") + " | Final visible gap from H: " + (float.IsNaN(num5) ? "n/a" : (((num5 >= 0f) ? "+" : "") + num5.ToString("F1", CultureInfo.InvariantCulture) + "m")), "Visible card quads: H..H+100m " + _visibleCardQuadsHandoffTo100 + " | H+100..H+350m " + _visibleCardQuadsHandoff100To350 + " | Hidden start floor: " + (flag ? "HIDDEN START FLOOR ACTIVE" : "none") + " | Exact start source: " + text, "Exact first stage losing the nearest candidate: " + text2, "-- Guaranteed handoff-fill band (H to H+" + Mathf.RoundToInt(HandoffFillBandWidth()) + "m) --", "Enable Guaranteed Handoff Fill: " + (HandoffFillEnabled() ? "ON" : "off") + " | Uses biome density: " + ((_handoffFillUsesBiomeDensity != null && _handoffFillUsesBiomeDensity.Value) ? "yes" : "no") + " | Requires valid forest land: " + ((_handoffFillRequiresValidForestLand != null && _handoffFillRequiresValidForestLand.Value) ? "yes" : "no"), "In-band candidate tests: " + _handoffFillBandCandidatesSeen + " | Forced attempts: " + _handoffFillBandCandidatesForced + " | Skipped by chance despite bias: " + _handoffFillBandCandidatesSkippedByChance + " | Accepted handoff card centres: " + _handoffFillBandCandidatesFilled, "Spatial coverage slots accepted/target: " + Math.Min(_handoffFillBandCandidatesFilled, HandoffFillRequiredSpatialSlots()) + "/" + HandoffFillRequiredSpatialSlots() + " (" + (HandoffFillSpatialCoverageRatio() * 100f).ToString("F0", CultureInfo.InvariantCulture) + "%) | Largest observed accepted-to-accepted gap: " + _handoffFillLargestObservedGap.ToString("F1", CultureInfo.InvariantCulture) + "m | Maximum allowed: " + HandoffFillMaximumGap().ToString("F0", CultureInfo.InvariantCulture) + "m | Violations: " + _handoffFillBandGapViolations, HandoffFillCoverageStatus(), text3 }; for (int i = 0; i < array.Length; i++) { GUI.Label(new Rect(num + 12f, num2 + 22f + (float)i * 20f, 1356f, 20f), array[i], _overlayStyle); } } private static string FormatTraceDistance(float value) { if (!(value < float.MaxValue)) { return "none observed this window"; } return value.ToString("F1", CultureInfo.InvariantCulture) + "m"; } private void DrawHorizonCoveragePanel() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_19fd: Unknown result type (might be due to invalid IL or missing references) float num = 12f; float num2 = 12f; GUI.Box(new Rect(num, num2, 1380f, 1160f), "New Horizons Treelines v4.6.31 -- Golden Density / Black Forest / Coverage Diagnostics (page 10/10)"); UpdateRingSectorCoverageState(); RingPlaneCounts[] array = ComputeRingPlaneCounts(); int num3 = GlobalTreeCardPlaneBudget(); int num4 = GlobalCanopyPlaneBudget(); int num5 = CountTreeCards(); int num6 = CountCanopyCards(); int treeDiff; int canopyDiff; bool flag = ActiveBudgetAccountingOk(out treeDiff, out canopyDiff); string text = "none -- "; string text2 = "HORIZON COVERAGE OK"; for (int num7 = 4; num7 >= 0; num7--) { ForestRing forestRing = (ForestRing)num7; if (RingHasPendingWork(forestRing) || _ringBuiltChunkCounts[num7] > 0) { bool flag2 = array[num7].Tree > 0 || array[num7].Canopy > 0; bool flag3 = _ringVisibleChunkCounts[num7] > 0; if (_ringEmptyValidSectors[num7] > 0) { text2 = "HORIZON PRIMARY COVERAGE PENDING"; text = RingNames[num7] + " ring: " + _ringEmptyValidSectors[num7] + " valid-land sector(s) still lack primary tree coverage; " + _ringPendingPrimaryJobs[num7] + " primary job(s) pending"; break; } if (!flag2 && !RingHasPendingWork(forestRing)) { text2 = "HORIZON CANDIDATES REJECTED"; text = RingNames[num7] + " ring: tiles built but zero cards committed (density/biome/grounding/water rejected every candidate)"; break; } if (flag2 && !flag3) { text2 = "HORIZON RENDERERS INVISIBLE"; text = RingNames[num7] + " ring: " + array[num7].Tree + " tree + " + array[num7].Canopy + " canopy planes committed, but 0 renderers currently visible"; break; } if (_currentBudgetStarvationDetected && _currentBudgetStarvationRing == forestRing) { text2 = "HORIZON BUDGET STARVATION"; text = RingNames[num7] + " ring: ring-aware tree/canopy budget was 0 on last build attempt"; break; } } } if (text2 == "HORIZON COVERAGE OK") { text = "none -- every ring with pending or built work currently has visible coverage"; } string[] array2 = new string[96]; int num8 = 0; array2[num8++] = "-- GOLDEN HIGH DENSITY --"; array2[num8++] = "Active density preset: " + ((_treeCardDensityPreset != null) ? _treeCardDensityPreset.Value.ToString() : "unbound") + " | manual/custom values preserved: " + (_manualTreeCardValuesPreserved ? "YES" : "no"); array2[num8++] = "Requested candidate total per tile: " + EffectiveMaximumCandidateCellsPerTileBuild() + " | active cursor: " + _forestCurrentJobCandidateIndex + "/" + _forestCurrentJobCandidateTotal + " | partial resumable tiles: " + _forestPartiallyProcessedResumableTiles + " | completed evaluations: " + _forestCompletedCandidateEvaluations + " across " + _forestTilesCompletedFullCandidateSet + " full tiles"; array2[num8++] = "Baseline cards accepted: " + _baselinePrimaryCardsAccepted + " | reinforcement cards accepted: " + _reinforcementCardsAccepted + " | average cards/completed tile: " + ((_forestTilesCompletedFullCandidateSet > 0) ? ((double)(_baselinePrimaryCardsAccepted + _reinforcementCardsAccepted) / (double)_forestTilesCompletedFullCandidateSet).ToString("F1", CultureInfo.InvariantCulture) : "n/a"); array2[num8++] = "Blocked: candidate completion " + _cardsBlockedByCandidateCompletion + " | cluster cap " + _cardsBlockedByClusterCap + " | plane cap " + _cardsBlockedByPlaneCap + " | global budget " + _cardsBlockedByGlobalBudget + " | ring reservation " + _cardsBlockedByRingReservation; array2[num8++] = "Other limits: reinforcement cap " + _cardsBlockedByReinforcementCap + " | optional defer " + _cardsBlockedByOptionalDefer + " | bootstrap safety " + _cardsBlockedByBootstrapSafety + " | mesh vertex/index " + _cardsBlockedByMeshLimit; array2[num8++] = "-- BLACK FOREST COMPOSITION --"; array2[num8++] = "Tall pine atlas index: " + _blackForestTallPineAtlasIndex + " | atlas cell selections 0/1/2/3: " + _blackForestAtlasCellSelections[0] + "/" + _blackForestAtlasCellSelections[1] + "/" + _blackForestAtlasCellSelections[2] + "/" + _blackForestAtlasCellSelections[3]; array2[num8++] = "Tall pine selected: " + TotalBlackForestTallPineSelections() + " | other conifer selected: " + Math.Max(0L, _blackForestAcceptedCardTotal - TotalBlackForestTallPineSelections()) + " | accepted Black Forest cards: " + _blackForestAcceptedCardTotal + " | rejected during atlas selection: " + _blackForestAtlasSelectionRejected + " | proportional scale fallbacks: " + _blackForestScaleFallbacks; array2[num8++] = "Pine percentage by ring Handoff/Near/Mid/Far/Horizon: " + BlackForestPinePercentageText(0) + "/" + BlackForestPinePercentageText(1) + "/" + BlackForestPinePercentageText(2) + "/" + BlackForestPinePercentageText(3) + "/" + BlackForestPinePercentageText(4); array2[num8++] = "BLACK FOREST CARD DIMENSIONS: " + _blackForestPineDimensionSample; int[] array3 = new int[5]; long[] array4 = new long[5]; long[] array5 = new long[5]; long[] array6 = new long[5]; CollectTreeRendererPerformanceDiagnostics(array3, array4, array5, array6, out var shadowCasters, out var shadowReceivers, out var motionVectors, out var lightProbes, out var reflectionProbes); UpdateTreeMaterialRateForDiagnostics(); double num9 = ((_atlasTightenedPlaneSamples > 0) ? (_atlasTightenedQuadAreaSum / (double)_atlasTightenedPlaneSamples) : 0.0); double num10 = ((double)_visibleDetailedCrossedCards * 2.0 + (double)_visibleDetailedSinglePlaneCards) * num9; array2[num8++] = "-- FOREST VIEW RENDERING PERFORMANCE --"; array2[num8++] = "Cutout material: " + (_treeCardCutoutMaterialValid ? "VALID" : "INVALID") + " | " + _treeCardCutoutMaterialDetail; array2[num8++] = "Atlas quad area average original/tightened: " + AtlasAverageArea(_atlasOriginalQuadAreaSum, _atlasTightenedPlaneSamples) + "/" + AtlasAverageArea(_atlasTightenedQuadAreaSum, _atlasTightenedPlaneSamples) + " | transparent-area reduction " + AtlasReductionPercent(_atlasOriginalQuadAreaSum, _atlasTightenedQuadAreaSum); array2[num8++] = "Atlas-cell reduction 0/1/2/3: " + AtlasCellReductionPercent(0) + "/" + AtlasCellReductionPercent(1) + "/" + AtlasCellReductionPercent(2) + "/" + AtlasCellReductionPercent(3) + " | tall-pine cell " + _blackForestTallPineAtlasIndex + " reduction " + AtlasCellReductionPercent(_blackForestTallPineAtlasIndex); array2[num8++] = "Atlas mip levels tree/canopy/mountain/swamp: " + _treeAtlasMipCount + "/" + _canopyAtlasMipCount + "/" + _mountainAtlasMipCount + "/" + _swampAtlasMipCount; array2[num8++] = "Renderer feature violations: shadow casters " + shadowCasters + " | receivers " + shadowReceivers + " | motion vectors " + motionVectors + " | light probes " + lightProbes + " | reflection probes " + reflectionProbes; array2[num8++] = "Visible logical/crossed/single-plane cards: " + _visibleDetailedLogicalCards + "/" + _visibleDetailedCrossedCards + "/" + _visibleDetailedSinglePlaneCards + " | renderers " + _visibleDetailedTreeRenderers; array2[num8++] = "Visible detailed triangles/vertices: " + _visibleDetailedTriangles + "/" + _visibleDetailedVertices + " | estimated visible alpha-tested quad area " + num10.ToString("F0", CultureInfo.InvariantCulture) + "m2"; array2[num8++] = "Overload guard: " + _viewFacingForestOverloadState.ToString() + " (" + _viewFacingForestThresholdState + ") | triangles soft/hard " + ((_visibleDetailedTriangleSoftLimit != null) ? _visibleDetailedTriangleSoftLimit.Value : 220000) + "/" + ((_visibleDetailedTriangleHardLimit != null) ? _visibleDetailedTriangleHardLimit.Value : 320000) + " | renderers soft/hard " + ((_visibleTreeRendererSoftLimit != null) ? _visibleTreeRendererSoftLimit.Value : 450) + "/" + ((_visibleTreeRendererHardLimit != null) ? _visibleTreeRendererHardLimit.Value : 650) + " | transitions " + _viewFacingForestOverloadTransitions; array2[num8++] = "Tree material updates/sec " + _treeMaterialUpdatesPerSecond.ToString("F2", CultureInfo.InvariantCulture) + " | total passes " + _treeMaterialUpdatePasses + " | skipped interval/brightness " + _treeMaterialUpdatesSkippedByInterval + "/" + _treeMaterialUpdatesSkippedByBrightness + " | property-block writes " + _treePropertyBlockWrites + " | base interval " + ((_minimumTreeMaterialUpdateIntervalSeconds != null) ? _minimumTreeMaterialUpdateIntervalSeconds.Value.ToString("F2", CultureInfo.InvariantCulture) : "0.25") + "s"; array2[num8++] = "LOD starts Mid-hard/Far/Horizon: 1200/" + ((_farSinglePlaneLodStartDistance != null) ? _farSinglePlaneLodStartDistance.Value.ToString("F0", CultureInfo.InvariantCulture) : "1400") + "/" + ((_horizonSinglePlaneLodStartDistance != null) ? _horizonSinglePlaneLodStartDistance.Value.ToString("F0", CultureInfo.InvariantCulture) : "2600") + "m | cumulative triangles/alpha area avoided " + _farLodTrianglesAvoided + "/" + _farLodAlphaTestedAreaAvoided.ToString("F0", CultureInfo.InvariantCulture) + "m2"; array2[num8++] = "Renderer chunks Handoff/Near/Mid/Far/Horizon: " + BoundaryTreelineChunkSize().ToString("F0", CultureInfo.InvariantCulture) + "/" + NormalForestChunkSize().ToString("F0", CultureInfo.InvariantCulture) + "/" + ((_midForestChunkSize != null) ? _midForestChunkSize.Value.ToString("F0", CultureInfo.InvariantCulture) : "96") + "/" + ((_forestFarChunkSize != null) ? _forestFarChunkSize.Value.ToString("F0", CultureInfo.InvariantCulture) : "128") + "/" + ((_forestVeryFarChunkSize != null) ? _forestVeryFarChunkSize.Value.ToString("F0", CultureInfo.InvariantCulture) : "160") + "m (Horizon max 192) | shard splits card/triangle " + _rendererChunksSplitByCardLimit + "/" + _rendererChunksSplitByTriangleLimit; for (int i = 0; i < 5; i++) { double num11 = ((array3[i] > 0) ? ((double)array4[i] / (double)array3[i]) : 0.0); array2[num8++] = RingNames[i] + " render: visible renderers/draw calls " + array3[i] + " | visible card planes " + array4[i] + " | cards/renderer " + num11.ToString("F1", CultureInfo.InvariantCulture) + " | vertices " + array5[i] + " | triangles " + array6[i]; } array2[num8++] = "Post-mesh grounding: attempts " + _postMeshValidationAttempts + " | validated meshes " + _postMeshValidatedMeshes + " | corrected roots " + _postMeshRootFloatCorrections + " (" + _postMeshRootFloatCorrectionMetres.ToString("F2", CultureInfo.InvariantCulture) + "m) | unresolved epoch/total " + _postMeshEpochUnresolvedViolations + "/" + _postMeshTrueViolations + " | worst " + _postMeshWorstVisibleRootError.ToString("F2", CultureInfo.InvariantCulture) + "m"; array2[num8++] = "Determinism compare skips signature/partial " + _determinismComparisonsSkippedSignature + "/" + _determinismComparisonsSkippedPartial + " | duplicate warnings suppressed " + _determinismWarningsSuppressed; array2[num8++] = "-- Per-ring coverage (built / visible chunks, committed planes, reserved vs. used budget, pending jobs) --"; for (int j = 0; j < 5; j++) { ForestRing forestRing2 = (ForestRing)j; int num12 = 0; for (int k = 0; k < _forestAddQueue.Count; k++) { if (RingForDistance(_forestAddQueue[k].Distance) == forestRing2) { num12++; } } int num13 = Mathf.RoundToInt((float)num3 * RingTreeShare(forestRing2)); int num14 = Mathf.RoundToInt((float)num4 * RingCanopyShare(forestRing2)); string text3 = ((_ringVisibleChunkCounts[j] > 0) ? (Mathf.RoundToInt(_ringMinVisibleDistance[j]) + "-" + Mathf.RoundToInt(_ringMaxVisibleDistance[j]) + "m") : "none visible"); array2[num8++] = RingNames[j] + ": sectors " + _ringCoveredSectors[j] + "/" + _ringValidLandSectors[j] + " (empty " + _ringEmptyValidSectors[j] + ", primary pending " + _ringPendingPrimaryJobs[j] + ") | primary/optional tree " + array[j].PrimaryTree + "/" + array[j].OptionalTree + " (total " + array[j].Tree + "/" + num13 + ") | canopy " + array[j].Canopy + "/" + num14 + " | visible " + _ringVisibleChunkCounts[j] + " | jobs " + num12 + " | " + text3; } array2[num8++] = "-- Guaranteed continuous forest coverage (v4.6.11) -- gap check against real accepted-card positions --"; bool flag4 = false; for (int l = 0; l < 5; l++) { array2[num8++] = RingNames[l] + ": max observed gap " + _ringLargestObservedCoverageGap[l].ToString("F0", CultureInfo.InvariantCulture) + "m / limit " + RingMaximumCoverageGap((ForestRing)l).ToString("F0", CultureInfo.InvariantCulture) + "m | fallback attempted " + _ringCoverageFallbackAttempted[l] + ", accepted " + _ringCoverageFallbackAccepted[l] + ", unresolved " + _ringCoverageFallbackFailed[l] + " | rejections: slope " + _ringCoverageSlopeRejections[l] + " water " + _ringCoverageWaterRejections[l] + " grounding " + _ringCoverageGroundingRejections[l]; if (_ringCoverageFallbackFailed[l] > 0) { flag4 = true; } } array2[num8++] = "Black Forest dedicated hole-filling: standard fallback accepted " + _blackForestCoverageFallbackAccepted + " | dedicated second-pass (2x radius/attempts) accepted " + _blackForestCoverageSecondPassAccepted; array2[num8++] = "-- Iterative coverage repair, ACTIVE state (v4.6.13 Task 3) --"; bool flag5 = false; ForestRing forestRing3 = ForestRing.Handoff; long num15 = -1L; for (int m = 0; m < 5; m++) { long num16 = _ringValidCellsScanned[m]; long num17 = _ringCoveredCellsScanned[m]; string text4 = ((num16 > 0) ? (Mathf.RoundToInt(100f * (float)num17 / (float)num16) + "%") : "n/a"); array2[num8++] = RingNames[m] + ": valid cells scanned " + num16 + " | covered " + num17 + " (" + text4 + ") | repair jobs pending " + _ringRepairJobsPending[m] + " | repairs accepted " + _ringRepairsAccepted[m] + " | retries exhausted " + _ringRepairRetriesExhausted[m]; if (_ringRepairJobsPending[m] > 0) { flag5 = true; if (_ringRepairJobsPending[m] > num15) { num15 = _ringRepairJobsPending[m]; forestRing3 = (ForestRing)m; } } } array2[num8++] = "Total active repair queue: " + _coverageRepairQueue.Count + " job(s) pending"; bool flag6 = _coverageRepairQueue.Count == 0 && !flag5; array2[num8++] = (flag6 ? "CONTINUOUS FOREST COVERAGE OK" : ("VISIBLE FOREST GAPS REMAIN -- worst active: ring " + forestRing3.ToString() + " (" + num15 + " pending repair jobs)" + (flag4 ? (" | historical worst: biome " + _worstCoverageBiome + ", ring " + _worstCoverageRing.ToString() + ", gap " + _worstCoverageGap.ToString("F0", CultureInfo.InvariantCulture) + "m, cause " + _worstCoverageRejectionCause) : ""))); array2[num8++] = "-- Global budget accounting --"; array2[num8++] = "Active global tree budget: " + num5 + "/" + num3 + " | Active global canopy budget: " + num6 + "/" + num4; array2[num8++] = "Cached inactive tree+canopy planes: " + SumCachedPlanes() + " (pooled tiles, not counted against the active budget above) | Retired pending destruction: " + _forestRetirementQueue.Count + " tiles"; array2[num8++] = "Planes added this update: " + _forestPlanesAddedThisUpdate + " | Planes removed this update: " + _forestPlanesRemovedThisUpdate + " | Budget reconciliation corrections: " + _budgetReconciliationCorrections + " | Maximum drift ever observed: " + _maxBudgetAccountingDriftObserved; array2[num8++] = "Reported active tree/canopy: " + _activeTreePlanesReported + "/" + _activeCanopyPlanesReported + " | Calculated (live) tree/canopy: " + num5 + "/" + num6 + " | Difference: " + treeDiff + "/" + canopyDiff; array2[num8++] = (flag ? "ACTIVE BUDGET ACCOUNTING OK" : ("ACTIVE BUDGET ACCOUNTING VIOLATION (tree diff " + treeDiff + ", canopy diff " + canopyDiff + ")")); array2[num8++] = "Ring Budget Reservation: " + ((_enableRingBudgetReservation != null && _enableRingBudgetReservation.Value) ? "ON" : "off (single shared pool)") + " | Redistribution: " + ((_allowUnusedRingBudgetRedistribution != null && _allowUnusedRingBudgetRedistribution.Value) ? "ON" : "off") + " | All-ring primary coverage complete: " + (PrimaryTreeCoverageComplete() ? "YES" : "no -- completed rings may already reinforce independently") + " | Last built tile ring: " + _lastBuiltTileRing; array2[num8++] = "-- Mesh output validation (Part 12) --"; array2[num8++] = "Meshes validated OK: " + _forestMeshesValidated + " | Rejected invalid: " + _forestMeshesRejectedInvalid + " | " + (_forestMeshValidationOk ? "FOREST MESH OUTPUT OK" : ("FOREST MESH OUTPUT VIOLATION (" + _forestMeshValidationViolationDetail + ")")); array2[num8++] = "-- Proven failure classification --"; array2[num8++] = "First pipeline collapse stage: " + text; array2[num8++] = "Current budget starvation ring: " + (_currentBudgetStarvationDetected ? _currentBudgetStarvationRing.ToString() : "none"); array2[num8++] = "Horizon coverage: " + HorizonCoveragePercentageText(); array2[num8++] = text2; for (int n = 0; n < num8; n++) { GUI.Label(new Rect(num + 12f, num2 + 22f + (float)n * 20f, 1356f, 20f), array2[n], _overlayStyle); } } private static string AtlasAverageArea(double sum, long count) { if (count <= 0) { return "n/a"; } return (sum / (double)count).ToString("F1", CultureInfo.InvariantCulture); } private void UpdateTreeMaterialRateForDiagnostics() { float realtimeSinceStartup = Time.realtimeSinceStartup; if (_treeMaterialRateLastSampleRealtime < 0f) { _treeMaterialRateLastSampleRealtime = realtimeSinceStartup; _treeMaterialRateLastPassCount = _treeMaterialUpdatePasses; return; } float num = realtimeSinceStartup - _treeMaterialRateLastSampleRealtime; if (!(num < 0.5f)) { _treeMaterialUpdatesPerSecond = (float)(_treeMaterialUpdatePasses - _treeMaterialRateLastPassCount) / Mathf.Max(0.001f, num); _treeMaterialRateLastSampleRealtime = realtimeSinceStartup; _treeMaterialRateLastPassCount = _treeMaterialUpdatePasses; } } private static string AtlasReductionPercent(double original, double tightened) { if (!(original > 0.0001)) { return "n/a"; } return (100.0 * (1.0 - tightened / original)).ToString("F1", CultureInfo.InvariantCulture) + "%"; } private string AtlasCellReductionPercent(int cell) { int num = Mathf.Clamp(cell, 0, 3); if (_atlasAreaSamplesByCell[num] <= 0) { return "n/a"; } return AtlasReductionPercent(_atlasOriginalAreaByCell[num], _atlasTightenedAreaByCell[num]); } private void CollectTreeRendererPerformanceDiagnostics(int[] renderers, long[] cards, long[] vertices, long[] triangles, out int shadowCasters, out int shadowReceivers, out int motionVectors, out int lightProbes, out int reflectionProbes) { shadowCasters = (shadowReceivers = (motionVectors = (lightProbes = (reflectionProbes = 0)))); foreach (ForestTile value in _forestTiles.Values) { if (value != null) { for (int i = 0; i < value.Chunks.Count; i++) { ForestChunk forestChunk = value.Chunks[i]; int ring = Mathf.Clamp((int)RingForDistance(FlatDistance(_buildAnchor.x, _buildAnchor.z, forestChunk.Center.x, forestChunk.Center.z)), 0, 4); AccumulateTreeRendererDiagnostics(forestChunk.TreeRenderer, forestChunk.TreeCardMesh, ring, renderers, cards, vertices, triangles, ref shadowCasters, ref shadowReceivers, ref motionVectors, ref lightProbes, ref reflectionProbes); AccumulateTreeRendererDiagnostics(forestChunk.CanopyRenderer, forestChunk.CanopyMesh, ring, renderers, cards, vertices, triangles, ref shadowCasters, ref shadowReceivers, ref motionVectors, ref lightProbes, ref reflectionProbes); AccumulateTreeRendererDiagnostics(forestChunk.MountainBiomeRenderer, forestChunk.MountainBiomeMesh, ring, renderers, cards, vertices, triangles, ref shadowCasters, ref shadowReceivers, ref motionVectors, ref lightProbes, ref reflectionProbes); AccumulateTreeRendererDiagnostics(forestChunk.SwampBiomeRenderer, forestChunk.SwampBiomeMesh, ring, renderers, cards, vertices, triangles, ref shadowCasters, ref shadowReceivers, ref motionVectors, ref lightProbes, ref reflectionProbes); } } } } private static void AccumulateTreeRendererDiagnostics(MeshRenderer renderer, Mesh mesh, int ring, int[] renderers, long[] cards, long[] vertices, long[] triangles, ref int shadowCasters, ref int shadowReceivers, ref int motionVectors, ref int lightProbes, ref int reflectionProbes) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 //IL_003c: 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) if (!((Object)(object)renderer == (Object)null)) { if ((int)((Renderer)renderer).shadowCastingMode != 0) { shadowCasters++; } if (((Renderer)renderer).receiveShadows) { shadowReceivers++; } if ((int)((Renderer)renderer).motionVectorGenerationMode != 2) { motionVectors++; } if ((int)((Renderer)renderer).lightProbeUsage != 0) { lightProbes++; } if ((int)((Renderer)renderer).reflectionProbeUsage != 0) { reflectionProbes++; } if (((Renderer)renderer).enabled && !((Object)(object)mesh == (Object)null)) { long num = ((mesh.subMeshCount > 0) ? ((long)mesh.GetIndexCount(0) / 3L) : 0); renderers[ring]++; cards[ring] += num / 2; vertices[ring] += mesh.vertexCount; triangles[ring] += num; } } } private long TotalBlackForestTallPineSelections() { long num = 0L; for (int i = 0; i < _blackForestTallPineSelectionsByRing.Length; i++) { num += _blackForestTallPineSelectionsByRing[i]; } return num; } private string BlackForestPinePercentageText(int ringIndex) { long num = _blackForestSelectionsByRing[ringIndex]; if (num <= 0) { return "n/a"; } return (100.0 * (double)_blackForestTallPineSelectionsByRing[ringIndex] / (double)num).ToString("F1", CultureInfo.InvariantCulture) + "%"; } private long SumCachedPlanes() { long num = 0L; foreach (ForestTile value in _forestTileCache.Values) { num += value.TreeCardCount + value.CanopyCardCount; } return num; } private string HorizonCoveragePercentageText() { int num = 0; int num2 = 0; for (int i = 0; i < 5; i++) { ForestRing ring = (ForestRing)i; if (RingHasPendingWork(ring) || _ringBuiltChunkCounts[i] != 0) { num++; if (_ringVisibleChunkCounts[i] > 0) { num2++; } } } if (num == 0) { return "n/a (no rings currently in range)"; } return num2 + "/" + num + " rings (" + Mathf.RoundToInt(100f * (float)num2 / (float)num) + "%)"; } private static string KeyLabel(ConfigEntry entry) { //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) if (entry == null) { return "?"; } return ((object)entry.Value/*cast due to .constrained prefix*/).ToString(); } private int CountForestClusters() { int num = 0; foreach (ForestTile value in _forestTiles.Values) { num += value.ClusterCount; } return num; } private int CountTreeCards() { int num = 0; foreach (ForestTile value in _forestTiles.Values) { num += value.TreeCardCount; } return num; } private int CountCanopyCards() { int num = 0; foreach (ForestTile value in _forestTiles.Values) { num += value.CanopyCardCount; } return num; } private bool TileInsideWorld(int x, int z, float tile) { float num = (float)x * tile; float num2 = num + tile; float num3 = (float)z * tile; float num4 = num3 + tile; if (!InsideWorld(num, num3) && !InsideWorld(num, num4) && !InsideWorld(num2, num3) && !InsideWorld(num2, num4)) { return InsideWorld((num + num2) * 0.5f, (num3 + num4) * 0.5f); } return true; } private bool InsideWorld(float x, float z) { if (_provider == null) { return false; } return x * x + z * z <= _provider.WorldRadius * _provider.WorldRadius; } private float ContinuityStart() { return EffectiveTreeCardStart(); } private float ContinuityEnd() { return FinalForestRange(); } private float TreeCardEnd() { return Mathf.Min(FinalForestRange(), NativeTreelineHandoff() + ExtensionDistance() * 0.85f); } private float SwampTreeCardEnd(Biome biome) { return TreeCardEnd(); } private float CanopyHandoffOffset() { return Mathf.Clamp((_canopyHandoffOffset != null) ? _canopyHandoffOffset.Value : 1300f, 300f, 3000f); } private float CanopyStart() { return EffectiveTreeCardStart() + CanopyHandoffOffset(); } private float ContinuityTileSize() { return Mathf.Max(64f, (_continuityTileSize != null) ? _continuityTileSize.Value : 64f); } private float NormalForestChunkSize() { return Mathf.Clamp((_normalForestChunkSize != null) ? _normalForestChunkSize.Value : 64f, 32f, 128f); } private float BoundaryTreelineChunkSize() { float num = ((_nativeTreelineBoundaryChunkSize != null) ? _nativeTreelineBoundaryChunkSize.Value : 16f); return Mathf.Clamp(num, 4f, NormalForestChunkSize()); } private float ContinuityRebuildDistance() { return Mathf.Max(64f, (_continuityRebuildDistance != null) ? _continuityRebuildDistance.Value : 64f); } private float EffectiveMinimumMovementSyncIntervalSeconds() { float num = ((_minimumMovementSyncIntervalSeconds != null) ? _minimumMovementSyncIntervalSeconds.Value : 0.35f); float num2 = ((_maximumMovementSyncsPerSecond != null) ? _maximumMovementSyncsPerSecond.Value : 3f); float num3 = ((num2 > 0f) ? (1f / num2) : 0f); return Mathf.Max(num, num3); } private float ClusterCellSize() { if (_clusterCellSize == null || !(_clusterCellSize.Value > 0f)) { return 18f; } return Mathf.Max(12f, _clusterCellSize.Value); } private int MaximumClustersPerTile() { if (_maximumClustersPerTile == null || _maximumClustersPerTile.Value <= 0) { return 6799; } return _maximumClustersPerTile.Value; } private int MaxTreeCardPlanesPerTile() { if (_maxTreeCardPlanesPerTile == null || _maxTreeCardPlanesPerTile.Value <= 0) { return 10945; } return _maxTreeCardPlanesPerTile.Value; } private int MaxCanopyPlanesPerTile() { if (_maxCanopyPlanesPerTile == null || _maxCanopyPlanesPerTile.Value <= 0) { return 9906; } return Mathf.Max(9906, _maxCanopyPlanesPerTile.Value); } private float FarTerrainViewDistance() { return FinalForestRange(); } private float FarForestStartDistance() { return EffectiveTreeCardStart(); } private float FarForestEndDistance() { return FinalForestRange(); } private float FarTerrainTileSize() { return Mathf.Max(100f, (_farTerrainTileSize != null) ? _farTerrainTileSize.Value : 700f); } private int FarTerrainMeshResolution() { if (_farTerrainMeshResolution == null) { return 26; } return _farTerrainMeshResolution.Value; } private int MaxTerrainTiles() { int requested; string limitReason; return TerrainTileLimitInfo(out requested, out limitReason); } private int MaxForestTiles() { int requested; int roomAfterTerrain; string limitReason; return ForestTileLimitInfo(out requested, out roomAfterTerrain, out limitReason); } private int ForestTileLimitInfo(out int requested, out int roomAfterTerrain, out string limitReason) { requested = ActivePresetProfile()?.MaximumForestTiles ?? ((_maxForestTiles != null && _maxForestTiles.Value > 0) ? _maxForestTiles.Value : 2200); int num = MaxTerrainTiles(); roomAfterTerrain = Mathf.Max(0, PanicTileCeiling() - num); int num2 = 2800; int num3 = Mathf.Max(0, Mathf.Min(requested, Mathf.Min(roomAfterTerrain, num2))); if (num3 >= requested) { limitReason = "no clamp"; } else if (requested > num2 && num2 <= roomAfterTerrain) { limitReason = "forest slider ceiling " + num2.ToString(CultureInfo.InvariantCulture); } else { limitReason = "panic ceiling " + PanicTileCeiling().ToString(CultureInfo.InvariantCulture) + " - terrain " + num.ToString(CultureInfo.InvariantCulture); } return num3; } private int GlobalTreeCardPlaneBudget() { if (_globalTreeCardPlaneBudget == null || _globalTreeCardPlaneBudget.Value <= 0) { return 190000; } return _globalTreeCardPlaneBudget.Value; } private int GlobalCanopyPlaneBudget() { if (_globalCanopyPlaneBudget == null || _globalCanopyPlaneBudget.Value <= 0) { return 145000; } return _globalCanopyPlaneBudget.Value; } private float[] RingBoundaries() { float num = NativeTreelineHandoff(); float num2 = Mathf.Max(num, FinalForestRange()); float num3 = Mathf.Min(num + 350f, num2); float num4 = Mathf.Min(Mathf.Max(num3, 1500f), num2); float num5 = Mathf.Min(Mathf.Max(num4, 4000f), num2); float num6 = Mathf.Min(Mathf.Max(num5, 7000f), num2); return new float[4] { num3, num4, num5, num6 }; } private ForestRing RingForDistance(float distance) { float[] array = RingBoundaries(); if (distance <= array[0]) { return ForestRing.Handoff; } if (distance <= array[1]) { return ForestRing.Near; } if (distance <= array[2]) { return ForestRing.Mid; } if (distance <= array[3]) { return ForestRing.Far; } return ForestRing.Horizon; } private int ForestCoverageSectorForTile(int tileX, int tileZ) { float num = ContinuityTileSize(); return ForestCoverageSector(((float)tileX + 0.5f) * num, ((float)tileZ + 0.5f) * num); } private void UpdateRingSectorCoverageState() { Array.Clear(_ringCoveredSectors, 0, _ringCoveredSectors.Length); Array.Clear(_ringEmptyValidSectors, 0, _ringEmptyValidSectors.Length); Array.Clear(_ringPendingPrimaryJobs, 0, _ringPendingPrimaryJobs.Length); bool[,] array = new bool[5, 16]; foreach (ForestTile value in _forestTiles.Values) { if (value != null && value.TreeCardCount > 0) { float distance = FlatDistance(_buildAnchor.x, _buildAnchor.z, value.Center.x, value.Center.z); int num = (int)RingForDistance(distance); int num2 = ForestCoverageSector(value.Center.x, value.Center.z); if (_ringSectorHasValidLand[num, num2]) { array[num, num2] = true; } } } for (int i = 0; i < 5; i++) { int num3 = 0; for (int j = 0; j < 16; j++) { if (_ringSectorHasValidLand[i, j] && array[i, j]) { num3++; } } _ringCoveredSectors[i] = num3; _ringEmptyValidSectors[i] = Mathf.Max(0, _ringValidLandSectors[i] - num3); } for (int k = 0; k < _forestAddQueue.Count; k++) { ForestAddJob forestAddJob = _forestAddQueue[k]; int num4 = (int)RingForDistance(forestAddJob.Distance); int num5 = ForestCoverageSectorForTile(forestAddJob.X, forestAddJob.Z); if (forestAddJob.IsPrimaryCoverage || (_ringSectorHasValidLand[num4, num5] && !array[num4, num5])) { _ringPendingPrimaryJobs[num4]++; } } } private bool RingPrimaryCoverageComplete(ForestRing ring) { if (_ringEmptyValidSectors[(int)ring] == 0 && _ringPendingPrimaryJobs[(int)ring] == 0) { return _ringRepairJobsPending[(int)ring] == 0; } return false; } private bool PrimaryTreeCoverageComplete() { for (int i = 0; i < 5; i++) { if (!RingPrimaryCoverageComplete((ForestRing)i)) { return false; } } return true; } private bool JobTargetsEmptyValidSector(ForestAddJob job) { int num = (int)RingForDistance(job.Distance); int num2 = ForestCoverageSectorForTile(job.X, job.Z); if (!_ringSectorHasValidLand[num, num2]) { return false; } foreach (ForestTile value in _forestTiles.Values) { if (value != null && value.TreeCardCount > 0) { float distance = FlatDistance(_buildAnchor.x, _buildAnchor.z, value.Center.x, value.Center.z); if (RingForDistance(distance) == (ForestRing)num && ForestCoverageSector(value.Center.x, value.Center.z) == num2) { return false; } } } return true; } private void QueueCoverageReinforcementJobs() { foreach (KeyValuePair forestTile in _forestTiles) { ForestTile value = forestTile.Value; if (value != null && value.PrimaryPassOnly && !_forestAddJobsByKey.ContainsKey(forestTile.Key)) { float distance = FlatDistance(_buildAnchor.x, _buildAnchor.z, value.Center.x, value.Center.z); if (RingPrimaryCoverageComplete(RingForDistance(distance))) { ForestAddJob forestAddJob = new ForestAddJob(value.TileX, value.TileZ, forestTile.Key, distance, _forestGenerationEpoch, Time.realtimeSinceStartup); forestAddJob.IsReinforcement = true; _forestAddQueue.Add(forestAddJob); _forestAddJobsByKey[forestTile.Key] = forestAddJob; } } } } private float RingTreeShare(ForestRing ring) { switch (ring) { case ForestRing.Handoff: if (_handoffMinimumTreeBudgetShare == null) { return 0.25f; } return Mathf.Clamp01(_handoffMinimumTreeBudgetShare.Value); case ForestRing.Near: if (_nearMinimumTreeBudgetShare == null) { return 0.2f; } return Mathf.Clamp01(_nearMinimumTreeBudgetShare.Value); case ForestRing.Mid: if (_midMinimumTreeBudgetShare == null) { return 0.2f; } return Mathf.Clamp01(_midMinimumTreeBudgetShare.Value); case ForestRing.Far: if (_farMinimumTreeBudgetShare == null) { return 0.2f; } return Mathf.Clamp01(_farMinimumTreeBudgetShare.Value); default: if (_horizonMinimumTreeBudgetShare == null) { return 0.15f; } return Mathf.Clamp01(_horizonMinimumTreeBudgetShare.Value); } } private float RingCanopyShare(ForestRing ring) { switch (ring) { case ForestRing.Handoff: if (_handoffMinimumCanopyBudgetShare == null) { return 0.25f; } return Mathf.Clamp01(_handoffMinimumCanopyBudgetShare.Value); case ForestRing.Near: if (_nearMinimumCanopyBudgetShare == null) { return 0.2f; } return Mathf.Clamp01(_nearMinimumCanopyBudgetShare.Value); case ForestRing.Mid: if (_midMinimumCanopyBudgetShare == null) { return 0.2f; } return Mathf.Clamp01(_midMinimumCanopyBudgetShare.Value); case ForestRing.Far: if (_farMinimumCanopyBudgetShare == null) { return 0.2f; } return Mathf.Clamp01(_farMinimumCanopyBudgetShare.Value); default: if (_horizonMinimumCanopyBudgetShare == null) { return 0.15f; } return Mathf.Clamp01(_horizonMinimumCanopyBudgetShare.Value); } } private RingPlaneCounts[] ComputeRingPlaneCounts() { RingPlaneCounts[] array = new RingPlaneCounts[5]; foreach (ForestTile value in _forestTiles.Values) { float distance = FlatDistance(_buildAnchor.x, _buildAnchor.z, value.Center.x, value.Center.z); ForestRing forestRing = RingForDistance(distance); array[(int)forestRing].Tree += value.TreeCardCount; array[(int)forestRing].Canopy += value.CanopyCardCount; int num = (value.PrimaryPassOnly ? value.TreeCardCount : Mathf.Min(1, value.TreeCardCount)); array[(int)forestRing].PrimaryTree += num; array[(int)forestRing].OptionalTree += Mathf.Max(0, value.TreeCardCount - num); } return array; } private bool RingHasPendingWork(ForestRing ring) { for (int i = 0; i < _forestAddQueue.Count; i++) { if (RingForDistance(_forestAddQueue[i].Distance) == ring) { return true; } } return false; } private int ComputeRingAwareTreeBudget(ForestRing ring, RingPlaneCounts[] ringCounts) { int num = GlobalTreeCardPlaneBudget(); int num2 = CountTreeCards(); int num3 = Mathf.Max(0, num - num2); if (_enableRingBudgetReservation == null || !_enableRingBudgetReservation.Value) { return num3; } int num4 = Mathf.RoundToInt((float)num * RingTreeShare(ring)); int tree = ringCounts[(int)ring].Tree; int num5 = Mathf.Max(0, num4 - tree); if (_allowUnusedRingBudgetRedistribution != null && !_allowUnusedRingBudgetRedistribution.Value) { return Mathf.Min(num3, num5); } int num6 = 0; for (int i = 0; i < 5; i++) { ForestRing forestRing = (ForestRing)i; if (forestRing != ring && !RingPrimaryCoverageComplete(forestRing)) { int num7 = Mathf.RoundToInt((float)num * RingTreeShare(forestRing)); num6 += Mathf.Max(0, num7 - ringCounts[i].Tree); } } int num8 = Mathf.Max(0, num3 - num5 - num6); return Mathf.Min(num3, num5 + num8); } private int ComputeRingAwareCanopyBudget(ForestRing ring, RingPlaneCounts[] ringCounts) { int num = GlobalCanopyPlaneBudget(); int num2 = CountCanopyCards(); int num3 = Mathf.Max(0, num - num2); if (_enableRingBudgetReservation == null || !_enableRingBudgetReservation.Value) { return num3; } int num4 = Mathf.RoundToInt((float)num * RingCanopyShare(ring)); int canopy = ringCounts[(int)ring].Canopy; int num5 = Mathf.Max(0, num4 - canopy); if (_allowUnusedRingBudgetRedistribution != null && !_allowUnusedRingBudgetRedistribution.Value) { return Mathf.Min(num3, num5); } int num6 = 0; for (int i = 0; i < 5; i++) { ForestRing forestRing = (ForestRing)i; if (forestRing != ring && !RingPrimaryCoverageComplete(forestRing)) { int num7 = Mathf.RoundToInt((float)num * RingCanopyShare(forestRing)); num6 += Mathf.Max(0, num7 - ringCounts[i].Canopy); } } int num8 = Mathf.Max(0, num3 - num5 - num6); return Mathf.Min(num3, num5 + num8); } private bool ActiveBudgetAccountingOk(out int treeDiff, out int canopyDiff) { treeDiff = _activeTreePlanesReported - CountTreeCards(); canopyDiff = _activeCanopyPlanesReported - CountCanopyCards(); int num = Mathf.Max(Mathf.Abs(treeDiff), Mathf.Abs(canopyDiff)); if (num > _maxBudgetAccountingDriftObserved) { _maxBudgetAccountingDriftObserved = num; } if (treeDiff == 0) { return canopyDiff == 0; } return false; } private float CameraFarClip() { return Mathf.Max((_mainCameraFarClip != null) ? _mainCameraFarClip.Value : 12500f, FinalForestRange() + 500f); } private static PresetRuntimeProfile ProfileForPreset(QualityPreset preset) { return preset switch { QualityPreset.VeryLow => VeryLowRuntimeProfile, QualityPreset.Low => LowRuntimeProfile, QualityPreset.Balanced => BalancedRuntimeProfile, QualityPreset.Medium => MediumRuntimeProfile, QualityPreset.High => HighRuntimeProfile, QualityPreset.Ultra => UltraRuntimeProfile, QualityPreset.Horizon => HorizonRuntimeProfile, _ => null, }; } private PresetRuntimeProfile ActivePresetProfile() { return ProfileForPreset((_qualityPreset != null) ? _qualityPreset.Value : QualityPreset.Custom); } private float DetectedNativeTreeViewDistance() { return Mathf.Max(1f, _nativeTreeViewDistance); } private float RawNativeTreelineRadius() { return ((_nativeTreelineMode == null) ? NativeTreelineMode.ManualCalibrated : _nativeTreelineMode.Value) switch { NativeTreelineMode.ManualCalibrated => Mathf.Max(1f, (_nativeTreelineCalibratedRadius != null) ? _nativeTreelineCalibratedRadius.Value : 215f), NativeTreelineMode.DefaultFallback => Mathf.Max(1f, (_nativeTreeViewDistanceFallback != null) ? _nativeTreeViewDistanceFallback.Value : 215f), _ => DetectedNativeTreeViewDistance(), }; } private float NativeTreelineHandoff() { if (_nativeTreelineMode != null && _nativeTreelineMode.Value == NativeTreelineMode.ManualCalibrated) { return Mathf.Max(0f, RawNativeTreelineRadius()); } float num = ((_nativeTreelineHandoffOffset != null) ? _nativeTreelineHandoffOffset.Value : 0f); return Mathf.Max(0f, RawNativeTreelineRadius() + num); } private bool ContinuousForestCoverageEnabled() { if (_enableContinuousForestCoverage != null) { return _enableContinuousForestCoverage.Value; } return true; } private float ContinuousCoverageTargetForBiome(Biome biome) { //IL_000e: 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_0052: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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) if (!ContinuousForestCoverageEnabled()) { return 0f; } if (IsSwampBiome(biome)) { if (_enableSwampTreeCards == null || _enableSwampTreeCards.Value) { if (_continuousSwampCoverage == null) { return 0.9f; } return Mathf.Clamp01(_continuousSwampCoverage.Value); } return 0f; } if ((biome & 8) != 0) { if (_continuousBlackForestCoverage == null) { return 1f; } return Mathf.Clamp01(_continuousBlackForestCoverage.Value); } if ((biome & 1) != 0) { if (_continuousMeadowsCoverage == null) { return 1f; } return Mathf.Clamp01(_continuousMeadowsCoverage.Value); } if ((biome & 4) != 0) { if (_continuousMountainCoverage == null) { return 0.9f; } return Mathf.Clamp01(_continuousMountainCoverage.Value); } if ((biome & 0x10) != 0) { if (_continuousPlainsCoverage == null) { return 0.2f; } return Mathf.Clamp01(_continuousPlainsCoverage.Value); } if ((biome & 0x200) != 0) { if (_continuousMistlandsCoverage == null) { return 0.7f; } return Mathf.Clamp01(_continuousMistlandsCoverage.Value); } if ((biome & 0x20) != 0) { return 0f; } if ((biome & 0x40) != 0) { if (_continuousDeepNorthCoverage == null) { return 0.5f; } return Mathf.Clamp01(_continuousDeepNorthCoverage.Value); } return 0.5f; } private float ContinuousCoverageGridRetention(ForestRing ring) { switch (ring) { case ForestRing.Handoff: case ForestRing.Near: if (_continuousNearGridRetention == null) { return 1f; } return Mathf.Clamp01(_continuousNearGridRetention.Value); case ForestRing.Mid: if (_continuousMidGridRetention == null) { return 1f; } return Mathf.Clamp01(_continuousMidGridRetention.Value); case ForestRing.Far: if (_continuousFarGridRetention == null) { return 0.85f; } return Mathf.Clamp01(_continuousFarGridRetention.Value); default: if (_continuousHorizonGridRetention == null) { return 0.7f; } return Mathf.Clamp01(_continuousHorizonGridRetention.Value); } } private float RingMaximumCoverageGap(ForestRing ring) { switch (ring) { case ForestRing.Handoff: if (_coverageHandoffMaximumGap == null) { return 18f; } return _coverageHandoffMaximumGap.Value; case ForestRing.Near: if (_coverageNearMaximumGap == null) { return 22f; } return _coverageNearMaximumGap.Value; case ForestRing.Mid: if (_coverageMidMaximumGap == null) { return 30f; } return _coverageMidMaximumGap.Value; case ForestRing.Far: if (_coverageFarMaximumGap == null) { return 42f; } return _coverageFarMaximumGap.Value; default: if (_coverageHorizonMaximumGap == null) { return 60f; } return _coverageHorizonMaximumGap.Value; } } private bool HandoffFillEnabled() { if (_enableHandoffFill != null) { return _enableHandoffFill.Value; } return true; } private float HandoffFillBandWidth() { if (_handoffFillBandWidth == null) { return 350f; } return Mathf.Clamp(_handoffFillBandWidth.Value, 64f, 600f); } private float HandoffFillCandidateSpacing() { if (_handoffFillCandidateSpacing == null) { return 10f; } return Mathf.Clamp(_handoffFillCandidateSpacing.Value, 6f, 40f); } private float HandoffFillMaximumGap() { if (_handoffFillMaximumGap == null) { return 20f; } return _handoffFillMaximumGap.Value; } private float HandoffFillCoverageTargetForBiome(Biome biome) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!HandoffFillEnabled()) { return 0f; } float result = ((_handoffFillMinimumCoverage != null) ? Mathf.Clamp01(_handoffFillMinimumCoverage.Value) : 0.85f); if (!_handoffFillUsesBiomeDensity.Value) { return result; } if (IsSwampBiome(biome)) { return result; } if ((biome & 8) != 0) { return 0.92f; } return result; } private bool HandoffFillEnforcesMaxGapForBiome(Biome biome) { //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_0008: Invalid comparison between Unknown and I4 return (biome & 0x100) == 0; } private void RecordHandoffFillGapCandidate(Biome biome, float x, float z) { _handoffFillBandCandidatesSkippedByChance++; } private void RecordHandoffFillAcceptedCandidate(Biome biome, float x, float z) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (HandoffFillEnforcesMaxGapForBiome(biome) && !float.IsNaN(_handoffFillLastRowAcceptedX)) { float num = FlatDistance(x, z, _handoffFillLastRowAcceptedX, _handoffFillLastRowZ); if (num > _handoffFillLargestObservedGap) { _handoffFillLargestObservedGap = num; } if (num > HandoffFillMaximumGap()) { _handoffFillBandGapViolations++; } } _handoffFillLastRowAcceptedX = x; _handoffFillLastRowZ = z; } private void RecordRingCoverageAcceptedCandidate(ForestRing ring, float nearestCardDistance, bool gapForced) { if (gapForced) { float num = ((nearestCardDistance >= float.MaxValue) ? RingMaximumCoverageGap(ring) : nearestCardDistance); if (num > _ringLargestObservedCoverageGap[(int)ring]) { _ringLargestObservedCoverageGap[(int)ring] = num; } _ringCoverageFallbackAccepted[(int)ring]++; } } private void RegisterCoverageBiomeAttempt(Biome biome) { } private void ComputeCandidateCardSize(float density, Biome biome, int seed, float distance, out float height, out float width, out int atlasIndex) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) height = Mathf.Lerp(10f, 28f, Mathf.Clamp01(density * 0.75f + Hash01(seed ^ 0x44F) * 0.25f)); if (IsMountainBiomeB(biome) && _enableMountainTreeCards.Value) { float num = Mathf.Lerp(0.9f, 1.3f, Hash01(seed ^ 0xD3F)); height = Mathf.Clamp(height * 1.35f * num, 18f, 32f); float num2 = Mathf.Lerp(0.45f, 0.78f, Hash01(seed ^ 0x1169)); float num3 = Mathf.Clamp(height * num2 * 1.2f, 10f, 18f); atlasIndex = ChooseMountainAtlasIndex(seed); float num4 = Mathf.Clamp(_mountainAtlasVisibleWidthFraction[atlasIndex], 0.1f, 1f); width = num3 / num4; } else if ((biome & 8) != 0) { ForestRing ring = RingForDistance(distance); float num5 = Mathf.Lerp((_blackForestMinimumRandomScale != null) ? _blackForestMinimumRandomScale.Value : 0.9f, (_blackForestMaximumRandomScale != null) ? _blackForestMaximumRandomScale.Value : 1.25f, Hash01(seed ^ 0x159B)); float num6 = 1.55f; height = Mathf.Clamp(height * num6 * num5, 16f, 25f); float num7 = Mathf.Lerp(0.42f, 0.72f, Hash01(seed ^ 0x19FD)); float num8 = 2f; float num9 = Mathf.Clamp(height * num7 * num8, 7f, 15f); atlasIndex = ChooseGoldenBlackForestSupportAtlasIndex(seed, ring); float num10 = Mathf.Clamp(_treeAtlasVisibleWidthFraction[atlasIndex], 0.1f, 1f); width = num9 / num10; } else { atlasIndex = ChooseTreeAtlasIndex(biome, seed); height *= BiomeCardHeightMultiplier(biome); width = height * Mathf.Lerp(0.42f, 0.72f, Hash01(seed ^ 0x8AD)) * BiomeCardWidthMultiplier(biome); } width = ClampGroundCardWidth(width, biome, CardPlacementKindForBiome(biome)); if (IsMountainBiomeB(biome)) { width = Mathf.Min(width, 22f); } if ((biome & 8) != 0) { width = Mathf.Min(width, 18f); } } private long CoverageRepairQueueKey(float x, float z, float cellSize) { float num = Mathf.Max(4f, cellSize); int x2 = Mathf.FloorToInt(x / num); int z2 = Mathf.FloorToInt(z / num); return TileKey(x2, z2); } private void ReleaseCoverageRepairQueueKey(CoverageRepairJob job) { if (job != null) { _coverageRepairQueuedKeys.Remove(job.QueueKey); } } private void ScanTileForCoverageHoles(ForestTile tile, ForestRing ring) { QueueCoverageSectorsForTile(tile, ring); } private static float CoverageSectorSize(ForestRing ring) { switch (ring) { case ForestRing.Handoff: case ForestRing.Near: return 48f; case ForestRing.Mid: return 72f; case ForestRing.Far: return 128f; default: return 192f; } } private static float CoverageDetectionRadius(ForestRing ring) { return ring switch { ForestRing.Handoff => 72f, ForestRing.Near => 96f, ForestRing.Mid => 160f, ForestRing.Far => 256f, _ => 384f, }; } private float CoverageTriggerGap(Biome biome, ForestRing ring) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) float num = RingMaximumCoverageGap(ring); if ((biome & 8) != 0) { return num * 0.75f; } if (IsMountainBiomeB(biome)) { return num * 0.85f; } return num; } private static bool IsCoverageRepairBiome(Biome biome) { //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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 if ((biome & 0x102) != 0) { return false; } return (biome & 0xD) > 0; } private void QueueCoverageSectorsForTile(ForestTile tile, ForestRing nominalRing) { if (tile == null || !ContinuousForestCoverageEnabled()) { return; } float num = (float)tile.TileX * tile.Size; float num2 = (float)tile.TileZ * tile.Size; for (int i = 0; i < 5; i++) { ForestRing forestRing = (ForestRing)i; float num3 = CoverageSectorSize(forestRing); int num4 = Mathf.FloorToInt(num / num3); int num5 = Mathf.FloorToInt(num2 / num3); int num6 = Mathf.FloorToInt((num + tile.Size - 0.01f) / num3); int num7 = Mathf.FloorToInt((num2 + tile.Size - 0.01f) / num3); for (int j = num5; j <= num7; j++) { for (int k = num4; k <= num6; k++) { float ax = ((float)k + 0.5f) * num3; float az = ((float)j + 0.5f) * num3; if (RingForDistance(FlatDistance(ax, az, _buildAnchor.x, _buildAnchor.z)) == forestRing) { CoverageSectorKey item = new CoverageSectorKey(k, j, forestRing, _forestGenerationEpoch); if (_coverageSectorKnownKeys.Add(item)) { _coverageSectorLightweightQueue.Enqueue(item); } } } } } } private void AdmitCoverageAuditJobs() { int num = ((_maximumActiveCoverageAuditJobs != null) ? Mathf.Clamp(_maximumActiveCoverageAuditJobs.Value, 1, 8) : 2); while (_activeCoverageAuditJobs.Count < num && _coverageSectorLightweightQueue.Count > 0) { CoverageSectorKey coverageSectorKey = _coverageSectorLightweightQueue.Dequeue(); if (coverageSectorKey.Epoch != _forestGenerationEpoch) { _coverageSectorKnownKeys.Remove(coverageSectorKey); _coverageAuditJobsCancelled++; continue; } float num2 = CoverageSectorSize(coverageSectorKey.Ring); float ax = ((float)coverageSectorKey.X + 0.5f) * num2; float az = ((float)coverageSectorKey.Z + 0.5f) * num2; float num3 = FlatDistance(ax, az, _buildAnchor.x, _buildAnchor.z); if (num3 < ContinuityStart() - num2 || num3 > ContinuityEnd() + num2) { _coverageSectorKnownKeys.Remove(coverageSectorKey); _coverageAuditJobsCancelled++; continue; } float num4 = Mathf.Max(8f, RingMaximumCoverageGap(coverageSectorKey.Ring) * 0.7f); int num5 = Mathf.Max(2, Mathf.CeilToInt(num2 / num4)); CoverageSectorJob coverageSectorJob = new CoverageSectorJob { Key = coverageSectorKey, CellCursor = 0, CellCount = num5 * num5, GridSide = num5, Dirty = true }; _activeCoverageAuditJobs.Add(coverageSectorJob); _activeCoverageSectorsByRing[(int)coverageSectorKey.Ring]++; _coverageRemainingCellsByRing[(int)coverageSectorKey.Ring] += coverageSectorJob.CellCount; } } private void ProcessCoverageAuditQueue() { //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) if (_provider == null || _activeForestBuild != null || !ContinuousForestCoverageEnabled()) { return; } AdmitCoverageAuditJobs(); if (_activeCoverageAuditJobs.Count == 0) { return; } int num = ((_coverageCellsPerResumableStep != null) ? Mathf.Clamp(_coverageCellsPerResumableStep.Value, 4, 128) : 24); int num2 = (_forestGenerationPressureMode ? Mathf.Min(8, num) : num); int num3 = 0; int num4 = ((_maximumCoverageRepairJobsAdmittedPerFrame == null) ? 1 : Mathf.Clamp(_maximumCoverageRepairJobsAdmittedPerFrame.Value, 1, 8)); int num5 = 0; int forestTerrainSamplesThisFrame = _forestTerrainSamplesThisFrame; int forestSlopeChecksThisFrame = _forestSlopeChecksThisFrame; int num6 = ((_terrainGroundSamplesPerResumableStep != null) ? Mathf.Clamp(_terrainGroundSamplesPerResumableStep.Value, 4, 128) : 24); int num7 = ((_slopeValidationsPerResumableStep != null) ? Mathf.Clamp(_slopeValidationsPerResumableStep.Value, 2, 64) : 16); Stopwatch stopwatch = Stopwatch.StartNew(); int num8 = _activeCoverageAuditJobs.Count - 1; while (num8 >= 0 && num5 < num2 && _forestTerrainSamplesThisFrame - forestTerrainSamplesThisFrame < num6 && _forestSlopeChecksThisFrame - forestSlopeChecksThisFrame < num7 && !ForestGenerationFrameBudgetExpired()) { CoverageSectorJob coverageSectorJob = _activeCoverageAuditJobs[num8]; float num9 = CoverageSectorSize(coverageSectorJob.Key.Ring); while (coverageSectorJob.CellCursor < coverageSectorJob.CellCount && num5 < num2 && _forestTerrainSamplesThisFrame - forestTerrainSamplesThisFrame < num6 && _forestSlopeChecksThisFrame - forestSlopeChecksThisFrame < num7 && !ForestGenerationFrameBudgetExpired()) { int num10 = coverageSectorJob.CellCursor++; int num11 = num10 % coverageSectorJob.GridSide; int num12 = num10 / coverageSectorJob.GridSide; int num13 = HashCombine(coverageSectorJob.Key.X, coverageSectorJob.Key.Z, num10 ^ ((int)coverageSectorJob.Key.Ring * 7919)); float num14 = (Hash01(num13 ^ 0x3F5) - 0.5f) * 0.35f; float num15 = (Hash01(num13 ^ 0x7E1) - 0.5f) * 0.35f; float num16 = ((float)coverageSectorJob.Key.X + ((float)num11 + 0.5f + num14) / (float)coverageSectorJob.GridSide) * num9; float num17 = ((float)coverageSectorJob.Key.Z + ((float)num12 + 0.5f + num15) / (float)coverageSectorJob.GridSide) * num9; num5++; _coverageAuditedCellsByRing[(int)coverageSectorJob.Key.Ring]++; _coverageRemainingCellsByRing[(int)coverageSectorJob.Key.Ring] = Math.Max(0L, _coverageRemainingCellsByRing[(int)coverageSectorJob.Key.Ring] - 1); _forestTerrainSamplesThisFrame++; float num18 = FlatDistance(num16, num17, _buildAnchor.x, _buildAnchor.z); if (num18 < ContinuityStart() || num18 > ContinuityEnd() || !_provider.TrySample(num16, num17, out var sample) || !sample.Valid || !IsCoverageRepairBiome(sample.Biome)) { continue; } _forestSlopeChecksThisFrame++; if (!CandidateSurfaceSupported(sample) || sample.SlopeDegrees >= BiomeMaxSlope(sample.Biome) || !TryGetWaterLevel(out var waterLevel) || sample.GroundY < waterLevel + 0.2f) { continue; } _ringValidCellsScanned[(int)coverageSectorJob.Key.Ring]++; float num19 = CoverageDetectionRadius(coverageSectorJob.Key.Ring); float nearestDistance; bool flag = TryFindNearestAcceptedCoverageCard(num16, num17, sample.Biome, num19, out nearestDistance); float num20 = CoverageTriggerGap(sample.Biome, coverageSectorJob.Key.Ring); if (flag && nearestDistance <= num20) { _ringCoveredCellsScanned[(int)coverageSectorJob.Key.Ring]++; continue; } coverageSectorJob.UnresolvedGapCells++; _coverageUnresolvedGapCells++; _coverageUncoveredCellsByRing[(int)coverageSectorJob.Key.Ring]++; float num21 = (flag ? nearestDistance : num19); _ringLargestObservedCoverageGap[(int)coverageSectorJob.Key.Ring] = Mathf.Max(_ringLargestObservedCoverageGap[(int)coverageSectorJob.Key.Ring], num21); if (num3 < num4 && (!_forestGenerationPressureMode || (coverageSectorJob.Key.Ring != ForestRing.Far && coverageSectorJob.Key.Ring != ForestRing.Horizon)) && QueueCoverageRepairJob(num16, num17, coverageSectorJob.Key.Ring, sample.Biome, num13)) { num3++; } } if (coverageSectorJob.CellCursor >= coverageSectorJob.CellCount) { coverageSectorJob.Completed = true; _activeCoverageSectorsByRing[(int)coverageSectorJob.Key.Ring] = Math.Max(0L, _activeCoverageSectorsByRing[(int)coverageSectorJob.Key.Ring] - 1); _activeCoverageAuditJobs.RemoveAt(num8); } else { _coverageAuditJobsRetained++; } num8--; } stopwatch.Stop(); if (stopwatch.Elapsed.TotalMilliseconds > (double)_forestLongestGroundingSliceMs) { _forestLongestGroundingSliceMs = (float)stopwatch.Elapsed.TotalMilliseconds; } } private bool QueueCoverageRepairJob(float x, float z, ForestRing ring, Biome biome, int stableSeed) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Invalid comparison between Unknown and I4 float num = CoverageTriggerGap(biome, ring); long num2 = CoverageRepairQueueKey(x, z, Mathf.Max(4f, num * 0.5f)); if (!_coverageRepairQueuedKeys.Add(num2)) { return false; } int attemptsRemaining = ((_coastalSearchMaximumAttempts != null) ? Mathf.Clamp(_coastalSearchMaximumAttempts.Value, 4, 96) : 32); _coverageRepairQueue.Add(new CoverageRepairJob { X = x, Z = z, Ring = ring, Biome = biome, QueueKey = num2, AttemptsRemaining = attemptsRemaining, StableRepairSeed = stableSeed, CoastalAttemptCursor = 0, CoastalSearchActive = ((biome & 9) > 0), QueuedRealtime = Time.realtimeSinceStartup }); _ringRepairJobsPending[(int)ring]++; return true; } private void ProcessCoverageRepairQueue() { //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_049a: Unknown result type (might be due to invalid IL or missing references) //IL_04a0: Unknown result type (might be due to invalid IL or missing references) if (_coverageRepairQueue.Count == 0) { return; } int num = ((_maximumCompletedForestTileCommitsPerFrame == null) ? 1 : Mathf.Clamp(_maximumCompletedForestTileCommitsPerFrame.Value, 1, 4)); if (_forestCompletedTileCommitsThisFrame >= num) { return; } if (_activeForestBuild != null) { _cardsBlockedByOptionalDefer++; return; } int num2 = ((_maximumCoverageRepairJobsAdmittedPerFrame == null) ? 1 : Mathf.Clamp(_maximumCoverageRepairJobsAdmittedPerFrame.Value, 1, 8)); int num3 = ((_coverageRepairHardJobsPerFrame == null) ? 1 : Mathf.Clamp(_coverageRepairHardJobsPerFrame.Value, 1, 4)); int num4 = Mathf.Min(num2, num3); int num5 = ((_maximumCoverageRepairCardsCommittedPerFrame == null) ? 1 : Mathf.Clamp(_maximumCoverageRepairCardsCommittedPerFrame.Value, 1, 4)); float num6 = Mathf.Min((_coverageRepairTimeBudgetMs != null) ? Mathf.Clamp(_coverageRepairTimeBudgetMs.Value, 0.05f, 2f) : 0.35f, _forestCurrentCpuBudgetMs); float num7 = ((_repairChunkRebuildCoalescingSeconds != null) ? Mathf.Max(0f, _repairChunkRebuildCoalescingSeconds.Value) : 0.3f); int num8 = 0; int num9 = 0; Stopwatch stopwatch = Stopwatch.StartNew(); int num10 = _coverageRepairQueue.Count - 1; while (num10 >= 0 && num8 < num4 && num9 < num5 && stopwatch.Elapsed.TotalMilliseconds < (double)num6 && !ForestGenerationFrameBudgetExpired()) { CoverageRepairJob coverageRepairJob = _coverageRepairQueue[num10]; if (IsSwampBiome(coverageRepairJob.Biome)) { ReleaseCoverageRepairQueueKey(coverageRepairJob); _coverageRepairQueue.RemoveAt(num10); _ringRepairJobsPending[(int)coverageRepairJob.Ring] = Math.Max(0L, _ringRepairJobsPending[(int)coverageRepairJob.Ring] - 1); } else if ((!_forestGenerationPressureMode || (coverageRepairJob.Ring != ForestRing.Far && coverageRepairJob.Ring != ForestRing.Horizon)) && !(Time.realtimeSinceStartup - coverageRepairJob.QueuedRealtime < num7)) { num8++; if (HasPrimaryCoverageCardWithin(coverageRepairJob.X, coverageRepairJob.Z, coverageRepairJob.Biome, CoverageTriggerGap(coverageRepairJob.Biome, coverageRepairJob.Ring), out var _)) { ReleaseCoverageRepairQueueKey(coverageRepairJob); _coverageRepairQueue.RemoveAt(num10); _ringRepairJobsPending[(int)coverageRepairJob.Ring] = Math.Max(0L, _ringRepairJobsPending[(int)coverageRepairJob.Ring] - 1); } else { int stableRepairSeed = coverageRepairJob.StableRepairSeed; ForestPlacementKind kind = CardPlacementKindForBiome(coverageRepairJob.Biome); if (!coverageRepairJob.DensityResolved) { coverageRepairJob.Density = 0.5f; if (_provider != null && _provider.TrySample(coverageRepairJob.X, coverageRepairJob.Z, out var sample) && sample.Valid) { coverageRepairJob.Density = Mathf.Clamp01(sample.ForestDensity * ForestDensityMultiplier()); } coverageRepairJob.DensityResolved = true; _forestTerrainSamplesThisFrame++; } float density = coverageRepairJob.Density; float distance = FlatDistance(coverageRepairJob.X, coverageRepairJob.Z, _buildAnchor.x, _buildAnchor.z); ComputeCandidateCardSize(density, coverageRepairJob.Biome, stableRepairSeed, distance, out var height, out var width, out var atlasIndex); bool flag = false; float finalX = coverageRepairJob.X; float finalZ = coverageRepairJob.Z; float finalDistance = FlatDistance(coverageRepairJob.X, coverageRepairJob.Z, _buildAnchor.x, _buildAnchor.z); Biome biome = coverageRepairJob.Biome; PlacementValidationResult validation = default(PlacementValidationResult); if (coverageRepairJob.CoastalSearchActive) { flag = TryStepCoverageCoastalRecovery(coverageRepairJob, width, height, kind, out finalX, out finalZ, out finalDistance, out var finalSample, out validation); if (flag) { biome = finalSample.Biome; } } else { _forestFootprintChecksThisFrame++; flag = ValidateAndLockCardToVisibleGround(coverageRepairJob.Biome, coverageRepairJob.X, coverageRepairJob.Z, width, height, finalDistance, kind, out validation); coverageRepairJob.AttemptsRemaining = 0; } if (flag && TryBuildCoverageRepairTile(finalX, finalZ, validation, biome, kind, finalDistance, density, height, width, atlasIndex, out var tile, out var ownerKey, out var addedRepairPlanes)) { _forestTiles[ownerKey] = tile; ActivatePrimaryCoverageRecord(finalX, finalZ, biome); _activeTreePlanesReported += addedRepairPlanes; _forestPlanesAddedThisUpdate += addedRepairPlanes; ReleaseCoverageRepairQueueKey(coverageRepairJob); _coverageRepairQueue.RemoveAt(num10); _ringRepairJobsPending[(int)coverageRepairJob.Ring] = Math.Max(0L, _ringRepairJobsPending[(int)coverageRepairJob.Ring] - 1); _ringRepairsAccepted[(int)coverageRepairJob.Ring]++; _coverageRepairCardsAccepted++; if ((coverageRepairJob.Biome & 8) != 0) { _blackForestCoverageFallbackAccepted++; } num9++; _forestCompletedTileCommitsThisFrame++; RequeueCoverageSectorAt(finalX, finalZ, coverageRepairJob.Ring); } else { if (!coverageRepairJob.CoastalSearchActive || coverageRepairJob.CoastalAttemptCursor >= ((_coastalSearchMaximumAttempts != null) ? _coastalSearchMaximumAttempts.Value : 32)) { coverageRepairJob.AttemptsRemaining = 0; } if (coverageRepairJob.AttemptsRemaining <= 0) { ReleaseCoverageRepairQueueKey(coverageRepairJob); _coverageRepairQueue.RemoveAt(num10); _ringRepairJobsPending[(int)coverageRepairJob.Ring] = Math.Max(0L, _ringRepairJobsPending[(int)coverageRepairJob.Ring] - 1); _ringRepairRetriesExhausted[(int)coverageRepairJob.Ring]++; } } } } num10--; } stopwatch.Stop(); float num11 = (float)stopwatch.Elapsed.TotalMilliseconds; if (num11 > _forestLongestGroundingSliceMs) { _forestLongestGroundingSliceMs = num11; } } private bool TryStepCoverageCoastalRecovery(CoverageRepairJob job, float width, float height, ForestPlacementKind kind, out float finalX, out float finalZ, out float finalDistance, out WorldSurfaceSample finalSample, out PlacementValidationResult validation) { //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) finalX = job.X; finalZ = job.Z; finalDistance = FlatDistance(job.X, job.Z, _buildAnchor.x, _buildAnchor.z); finalSample = default(WorldSurfaceSample); validation = default(PlacementValidationResult); int num = ((_coastalSearchMaximumAttempts != null) ? Mathf.Clamp(_coastalSearchMaximumAttempts.Value, 4, 96) : 32); int num2 = ((_coastalSearchAngularSamples != null) ? Mathf.Clamp(_coastalSearchAngularSamples.Value, 4, 32) : 16); int num3 = ((_coastalSearchAttemptsPerResumableStep != null) ? Mathf.Clamp(_coastalSearchAttemptsPerResumableStep.Value, 1, 16) : 4); if (_forestGenerationPressureMode) { num3 = 1; } float num4 = ((_coastalDryLandSearchRadius != null) ? Mathf.Clamp(_coastalDryLandSearchRadius.Value, 8f, 192f) : 96f); int num5 = Mathf.Max(1, Mathf.CeilToInt((float)num / (float)num2)); float num6 = Hash01(job.StableRepairSeed ^ 0x18365) * MathF.PI * 2f; int num7 = 0; while (job.CoastalAttemptCursor < num && num7 < num3 && !ForestGenerationFrameBudgetExpired()) { int num8 = job.CoastalAttemptCursor++; num7++; int num9 = num8 % num2; int num10 = num8 / num2; float num11 = num4 * ((float)num10 + 1f) / (float)num5; float num12 = num6 + (float)num9 * (MathF.PI * 2f / (float)num2); float num13 = job.X + Mathf.Cos(num12) * num11; float num14 = job.Z + Mathf.Sin(num12) * num11; float num15 = FlatDistance(num13, num14, _buildAnchor.x, _buildAnchor.z); _forestTerrainSamplesThisFrame++; _forestSlopeChecksThisFrame++; if (_provider != null && _provider.TrySample(num13, num14, out var sample) && sample.Valid && CoverageBiomesMatch(sample.Biome, job.Biome) && CandidateSurfaceSupported(sample) && !(sample.SlopeDegrees >= BiomeMaxSlope(sample.Biome)) && TryGetWaterLevel(out var waterLevel) && !(sample.GroundY < waterLevel + 0.2f)) { _forestFootprintChecksThisFrame++; if (ValidateAndLockCardToVisibleGround(sample.Biome, num13, num14, width, height, num15, kind, out var validation2)) { finalX = num13; finalZ = num14; finalDistance = num15; finalSample = sample; validation = validation2; _coastalLandRecoveryAccepted++; _coverageCoastalRecoveriesAccepted++; return true; } } } job.AttemptsRemaining = num - job.CoastalAttemptCursor; return false; } private void RequeueCoverageSectorAt(float x, float z, ForestRing ring) { float num = CoverageSectorSize(ring); CoverageSectorKey item = new CoverageSectorKey(Mathf.FloorToInt(x / num), Mathf.FloorToInt(z / num), ring, _forestGenerationEpoch); _coverageSectorKnownKeys.Remove(item); if (_coverageSectorKnownKeys.Add(item)) { _coverageSectorLightweightQueue.Enqueue(item); } } private bool TryBuildCoverageRepairTile(float x, float z, PlacementValidationResult validation, Biome biome, ForestPlacementKind kind, float distance, float density, float height, float width, int atlas, out ForestTile tile, out long ownerKey, out int addedRepairPlanes) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Invalid comparison between Unknown and I4 //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_04ee: Unknown result type (might be due to invalid IL or missing references) //IL_04f3: Unknown result type (might be due to invalid IL or missing references) //IL_04f5: Unknown result type (might be due to invalid IL or missing references) tile = null; ownerKey = 0L; addedRepairPlanes = 0; if (_provider == null) { return false; } int num = HashCombine(Mathf.RoundToInt(x * 4f), Mathf.RoundToInt(z * 4f), 811171); float angle = Hash01(num ^ 0x1E2B) * MathF.PI * 2f; _coverageRepairScratchVertices.Clear(); _coverageRepairScratchUvs.Clear(); _coverageRepairScratchTriangles.Clear(); List coverageRepairScratchVertices = _coverageRepairScratchVertices; List coverageRepairScratchUvs = _coverageRepairScratchUvs; List coverageRepairScratchTriangles = _coverageRepairScratchTriangles; bool flag = (biome & 8) > 0; bool flag2 = IsMountainBiomeB(biome) && _enableMountainTreeCards.Value; int num2 = Mathf.FloorToInt(x / 64f); int num3 = Mathf.FloorToInt(z / 64f); int num4 = (flag2 ? 1 : 0); long num5 = TileKey(2000000000 + (int)(_coverageRepairTileCounter % 400000000), (int)(_coverageRepairTileCounter >> 16)); _coverageRepairTileCounter++; _currentGroundCardOwnerTileKey = num5; float height2 = height; float width2 = width; int atlasIndex = atlas; PlacementValidationResult validation2 = validation; if (flag) { ComposeAcceptedBlackForestCard(density, num, distance, out height2, out width2, out atlasIndex); validation2 = RetargetAcceptedVisualValidation(validation, width2, height2); } else if (flag2) { ComposeAcceptedMountainCard(density, num, out height2, out width2, out atlasIndex); validation2 = RetargetAcceptedVisualValidation(validation, width2, height2); } int goldenBudgetPlanes = 0; bool singlePlaneLodUsed = false; int num6; try { num6 = (flag ? AddValidatedCrossedAtlasCards(coverageRepairScratchVertices, coverageRepairScratchUvs, coverageRepairScratchTriangles, x, validation2, validation2.FinalBaseY, z, width2, height2, angle, atlasIndex, 2, kind, biome, distance, 4, _viewFacingForestOverloadState, out goldenBudgetPlanes, out singlePlaneLodUsed) : AddValidatedAtlasCard(coverageRepairScratchVertices, coverageRepairScratchUvs, coverageRepairScratchTriangles, x, validation2, validation2.FinalBaseY, z, width2, height2, angle, atlasIndex, kind, biome, distance, 3)); if (flag && num6 == 0 && (Mathf.Abs(width2 - width) > 0.001f || Mathf.Abs(height2 - height) > 0.001f)) { ConstrainAcceptedBlackForestFallback(width2, height2, out width2, out height2); PlacementValidationResult validation3 = RetargetAcceptedVisualValidation(validation, width2, height2); num6 = AddValidatedCrossedAtlasCards(coverageRepairScratchVertices, coverageRepairScratchUvs, coverageRepairScratchTriangles, x, validation3, validation3.FinalBaseY, z, width2, height2, angle, atlasIndex, 2, kind, biome, distance, 4, _viewFacingForestOverloadState, out goldenBudgetPlanes, out singlePlaneLodUsed); } else if (flag2 && num6 == 0) { ConstrainAcceptedMountainFallback(width2, height2, out width2, out height2); PlacementValidationResult validation4 = RetargetAcceptedVisualValidation(validation, width2, height2); num6 = AddValidatedAtlasCard(coverageRepairScratchVertices, coverageRepairScratchUvs, coverageRepairScratchTriangles, x, validation4, validation4.FinalBaseY, z, width2, height2, angle, atlasIndex, kind, biome, distance, 3); } if ((flag || flag2) && num6 == 0) { BuildAcceptedSupportFallback(width, height, atlas, biome, out width2, out height2); PlacementValidationResult validation5 = RetargetAcceptedVisualValidation(validation, width2, height2); num6 = (flag ? AddValidatedCrossedAtlasCards(coverageRepairScratchVertices, coverageRepairScratchUvs, coverageRepairScratchTriangles, x, validation5, validation5.FinalBaseY, z, width2, height2, angle, atlasIndex, 2, kind, biome, distance, 4, _viewFacingForestOverloadState, out goldenBudgetPlanes, out singlePlaneLodUsed) : AddValidatedAtlasCard(coverageRepairScratchVertices, coverageRepairScratchUvs, coverageRepairScratchTriangles, x, validation5, validation5.FinalBaseY, z, width2, height2, angle, atlasIndex, kind, biome, distance, 3)); } } finally { _currentGroundCardOwnerTileKey = long.MinValue; } if (flag && num6 > 0) { RecordAcceptedBlackForestAtlasSelection(atlasIndex, RingForDistance(distance)); if (num6 >= 2) { _blackForestCrossedCardsEmitted++; } else { _blackForestSinglePlaneCardsDetected++; } } if (num6 <= 0) { DeactivateGroundCardRecordsForTile(num5, deleteRecords: true); return false; } bool flag3 = !flag || singlePlaneLodUsed; int num7 = 0; CoverageRepairMeshBuffer value; while (true) { ownerKey = TileKey(1000000000 + num2 * 16 + num4 * 8 + num7, 1000000000 + num3); if (!_coverageRepairMeshBuffers.TryGetValue(ownerKey, out value) || value == null) { break; } bool num8; if (!flag3) { if (value.Chunk != null) { num8 = value.Chunk.CrossedLogicalTreeCardCount >= 600; goto IL_03f0; } } else if (value.Chunk != null) { num8 = value.Chunk.SinglePlaneLogicalTreeCardCount >= 900; goto IL_03f0; } goto IL_03f6; IL_03f6: if (value.Vertices.Count + coverageRepairScratchVertices.Count <= 24000 && (value.Triangles.Count + coverageRepairScratchTriangles.Count) / 3 <= 20000) { break; } goto IL_042d; IL_03f0: if (num8) { goto IL_042d; } goto IL_03f6; IL_042d: num7++; } Material val = ((flag2 && (Object)(object)_mountainBiomeCardMaterial != (Object)null) ? _mountainBiomeCardMaterial : _treeCardMaterial); if ((Object)(object)val == (Object)null) { DeactivateGroundCardRecordsForTile(num5, deleteRecords: true); return false; } bool flag4 = _coverageRepairMeshBuffers.TryGetValue(ownerKey, out value) && value != null; if (!flag4) { value = RentCoverageRepairMeshBuffer(); } int count = value.Vertices.Count; int count2 = value.Uvs.Count; int count3 = value.Triangles.Count; Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor((float)num2 * 64f, 0f, (float)num3 * 64f); for (int i = 0; i < coverageRepairScratchVertices.Count; i++) { value.Vertices.Add(coverageRepairScratchVertices[i] - val2); } value.Uvs.AddRange(coverageRepairScratchUvs); for (int j = 0; j < coverageRepairScratchTriangles.Count; j++) { value.Triangles.Add(count + coverageRepairScratchTriangles[j]); } Stopwatch stopwatch = Stopwatch.StartNew(); Mesh val3 = CreateMesh("DonegalHorizonCoverageRepairChunk_" + num2 + "_" + num3 + "_" + num4 + "_s" + num7, value.Vertices, value.Uvs, value.Triangles); stopwatch.Stop(); _forestMeshUploadTimeThisFrameMs += (float)stopwatch.Elapsed.TotalMilliseconds; if ((Object)(object)val3 != (Object)null) { _forestMeshesUploadedThisFrame++; _forestLongestMeshUploadMs = Mathf.Max(_forestLongestMeshUploadMs, (float)stopwatch.Elapsed.TotalMilliseconds); } if ((Object)(object)val3 == (Object)null) { value.Vertices.RemoveRange(count, value.Vertices.Count - count); value.Uvs.RemoveRange(count2, value.Uvs.Count - count2); value.Triangles.RemoveRange(count3, value.Triangles.Count - count3); DeactivateGroundCardRecordsForTile(num5, deleteRecords: true); return false; } EnsureRoot(); bool enabled = false; ForestTile forestTile; ForestChunk forestChunk; if (flag4 && value.Tile != null && value.Chunk != null) { forestTile = value.Tile; forestChunk = value.Chunk; enabled = forestChunk.Enabled; if ((Object)(object)value.Mesh != (Object)null) { Object.Destroy((Object)(object)value.Mesh); } } else { forestTile = new ForestTile(num2, num3, 64f, _root.transform); forestChunk = new ForestChunk(num2, num3, 64f, forestTile.Root.transform, num7); forestTile.Chunks.Add(forestChunk); forestTile.PrimaryPassOnly = false; forestTile.IsCoverageRepair = true; forestTile.GeometryOverloadState = _viewFacingForestOverloadState; forestTile.GenerationSignatureBase = CurrentForestGenerationSignatureBase(); value.Tile = forestTile; value.Chunk = forestChunk; _coverageRepairMeshBuffers[ownerKey] = value; } if (flag2) { forestChunk.MountainBiomeFilter.sharedMesh = val3; forestChunk.MountainBiomeMesh = val3; ((Renderer)forestChunk.MountainBiomeRenderer).sharedMaterial = val; ConfigureTreeCardRenderer(forestChunk.MountainBiomeRenderer); } else { forestChunk.TreeFilter.sharedMesh = val3; forestChunk.TreeCardMesh = val3; ((Renderer)forestChunk.TreeRenderer).sharedMaterial = val; ConfigureTreeCardRenderer(forestChunk.TreeRenderer); } value.Mesh = val3; forestChunk.LogicalTreeCardCount++; if (flag3) { forestChunk.SinglePlaneLogicalTreeCardCount++; } else { forestChunk.CrossedLogicalTreeCardCount++; } forestChunk.RecalculateBounds(); forestChunk.SetEnabled(enabled); addedRepairPlanes = (flag ? goldenBudgetPlanes : (flag2 ? 1 : num6)); forestTile.TreeCardCount += addedRepairPlanes; forestTile.EstimatedVertexCount = val3.vertexCount; MoveGroundCardRecordsToTile(num5, ownerKey); tile = forestTile; return true; } private void RegisterMountainSizeSample(float height, float width) { _mountainHeightSampleSum += height; _mountainWidthSampleSum += width; _mountainSizeSampleCount++; } private int HandoffFillRequiredSpatialSlots() { float num = Mathf.Max(1f, HandoffFillBandWidth()); float num2 = Mathf.Max(1f, HandoffFillMaximumGap()); int num3 = Mathf.Max(1, Mathf.CeilToInt(num / num2)); int num4 = 0; if (_ringValidLandSectors != null && _ringValidLandSectors.Length != 0) { num4 = _ringValidLandSectors[0]; } num4 = Mathf.Max(1, num4); return num3 * num4; } private float HandoffFillSpatialCoverageRatio() { int num = HandoffFillRequiredSpatialSlots(); if (num <= 0) { return 0f; } return Mathf.Clamp01((float)_handoffFillBandCandidatesFilled / (float)num); } private string HandoffFillCoverageStatus() { if (!HandoffFillEnabled()) { return "HANDOFF FILL DISABLED"; } if (_handoffFillBandCandidatesSeen <= 0) { return "HANDOFF COVERAGE: no in-band candidates measured yet"; } int num = HandoffFillRequiredSpatialSlots(); float num2 = HandoffFillSpatialCoverageRatio(); float num3 = ((_handoffFillMinimumCoverage != null) ? Mathf.Clamp01(_handoffFillMinimumCoverage.Value) : 0.85f); int num4 = Mathf.Max(1, Mathf.CeilToInt((float)num * num3)); bool flag = _handoffFillBandCandidatesFilled >= num4; bool flag2 = _handoffFillBandGapViolations == 0; if (flag && flag2) { return "HANDOFF COVERAGE OK (spatial slots " + Math.Min(_handoffFillBandCandidatesFilled, num) + "/" + num + ", " + (num2 * 100f).ToString("F0", CultureInfo.InvariantCulture) + "%, largest observed gap " + _handoffFillLargestObservedGap.ToString("F1", CultureInfo.InvariantCulture) + "m)"; } string text = (flag2 ? ("only " + _handoffFillBandCandidatesFilled + " accepted handoff card centres; " + num4 + " required for " + num + " spatial slots at " + (num3 * 100f).ToString("F0", CultureInfo.InvariantCulture) + "% target") : (_handoffFillBandGapViolations + " gap(s) beyond " + HandoffFillMaximumGap().ToString("F0", CultureInfo.InvariantCulture) + "m on forest-supporting land (largest " + _handoffFillLargestObservedGap.ToString("F1", CultureInfo.InvariantCulture) + "m)")); return "HANDOFF COVERAGE INSUFFICIENT (" + text + ")"; } private float NativeTreelineSeamOverlap() { return Mathf.Max(0f, (_nativeTreelineSeamOverlap != null) ? _nativeTreelineSeamOverlap.Value : 16f); } private float EffectiveTreeCardStart() { return Mathf.Max(0f, NativeTreelineHandoff() - NativeTreelineSeamOverlap()); } private float ExtensionDistance() { return Mathf.Max(0f, (_newHorizonsExtensionDistance != null) ? _newHorizonsExtensionDistance.Value : 4000f); } private float ValidForestRange() { if (_provider != null && _provider.IsReady) { return Mathf.Max(0f, _provider.ValidForestRange); } return Mathf.Max(0f, _proceduralWorldRadius.Value - 500f); } private float UncappedCalculatedRange() { return NativeTreelineHandoff() + ExtensionDistance(); } private float FinalForestRange() { return Mathf.Min(UncappedCalculatedRange(), ValidForestRange()); } private string RangeClampReason() { float num = UncappedCalculatedRange(); float num2 = ValidForestRange(); if (num <= num2 + 0.5f) { return "none"; } return "world/provider boundary " + Mathf.RoundToInt(num2).ToString(CultureInfo.InvariantCulture) + "m capped " + Mathf.RoundToInt(num).ToString(CultureInfo.InvariantCulture) + "m (requested " + Mathf.RoundToInt(num).ToString(CultureInfo.InvariantCulture) + "m)"; } private int PanicTileCeiling() { return ActivePresetProfile()?.PanicTileCeiling ?? _panicTileCeiling.Value; } private int BaseTilesBuiltPerFrame() { return ActivePresetProfile()?.TilesBuiltPerFrame ?? _tilesBuiltPerFrame.Value; } private int TilesBuiltPerFrame() { if (!AdaptiveHighPresetGovernorActive()) { return BaseTilesBuiltPerFrame(); } return Mathf.Max(1, _adaptiveEffectiveTilesPerFrame); } private int BaseMaximumMeshUploadsPerFrame() { return 1; } private int MaximumMeshUploadsPerFrame() { return 1; } private bool CullFarTilesBehindCamera() { if (_cullBehindCamera != null) { return _cullBehindCamera.Value; } return true; } private float ForestDensityMultiplier() { return _forestDensityMultiplier.Value; } private float ForestDensityThreshold() { return _forestDensityThreshold.Value; } private float MixedCandidateDensityFloor() { return _mixedCandidateDensityFloor.Value; } private float SwampCandidateDensityFloor() { return _swampCandidateDensityFloor.Value; } private float MountainCandidateDensityFloor() { return _mountainCandidateDensityFloor.Value; } private float PlainsCandidateDensityFloor() { return _plainsCandidateDensityFloor.Value; } private float ForestTerrainTintStrength() { return _forestTerrainTintStrength.Value; } private float DistanceTintStrength() { return _terrainDistanceTintStrength.Value; } private float FarTreeAlpha() { return _farTreeAlpha.Value; } private float FarCanopyAlpha() { return _farCanopyAlpha.Value; } private float FarForestContrast() { return _farForestContrast.Value; } private float FarTerrainContrast() { return _farTerrainContrast.Value; } private float FarForestDarkness() { float value = _farForestDarkness.Value; return ApplyClearSkyTintReduction(value); } private float FarTerrainDarkness() { float value = _farTerrainDarkness.Value; return ApplyClearSkyTintReduction(value); } private float ApplyClearSkyTintReduction(float darkness) { if (_enableRealClearSkies == null || !_enableRealClearSkies.Value) { return darkness; } if (_clearSkyTier == ClearSkyWeatherTier.Bad || _clearSkyTier == ClearSkyWeatherTier.SpecialBiome) { return darkness; } float clearSkyAppliedTintMultiplier = _clearSkyAppliedTintMultiplier; return 1f - (1f - darkness) * clearSkyAppliedTintMultiplier; } private float ForestExclusionMarginScale() { if (_forestExclusionMarginScale == null) { return 0f; } return Mathf.Clamp01(_forestExclusionMarginScale.Value); } private int TerrainTileLimitInfo(out int requested, out string limitReason) { requested = ((_maxTerrainTiles != null && _maxTerrainTiles.Value > 0) ? _maxTerrainTiles.Value : 450); int num = 800; int num2 = Mathf.Max(0, Mathf.Min(requested, Mathf.Min(PanicTileCeiling(), num))); if (num2 >= requested) { limitReason = "no clamp"; } else if (requested > num && num <= PanicTileCeiling()) { limitReason = "terrain slider ceiling " + num.ToString(CultureInfo.InvariantCulture); } else { limitReason = "panic ceiling " + PanicTileCeiling().ToString(CultureInfo.InvariantCulture); } return num2; } private string BudgetClampReason() { int requested; string limitReason; int num = TerrainTileLimitInfo(out requested, out limitReason); int requested2; int roomAfterTerrain; string limitReason2; int num2 = ForestTileLimitInfo(out requested2, out roomAfterTerrain, out limitReason2); string text = ""; if (num < requested) { text = "terrain " + requested.ToString(CultureInfo.InvariantCulture) + " -> " + num.ToString(CultureInfo.InvariantCulture) + " (" + limitReason + ")"; } if (num2 < requested2) { if (text.Length > 0) { text += "; "; } text = text + "forest " + requested2.ToString(CultureInfo.InvariantCulture) + " -> " + num2.ToString(CultureInfo.InvariantCulture) + " (" + limitReason2 + ")"; } if (CountTreeCards() >= GlobalTreeCardPlaneBudget()) { if (text.Length > 0) { text += "; "; } text += "tree-card budget exhausted"; } if (CountCanopyCards() >= GlobalCanopyPlaneBudget()) { if (text.Length > 0) { text += "; "; } text += "canopy budget exhausted"; } if (text.Length != 0) { return text; } return "none"; } private int CountTerrainTileRequestsForBudget(float tile, float farDistance) { if (!_hasBuildAnchor || _provider == null || !_provider.IsReady) { return ApproximateTileRequestBudget(farDistance, tile); } int num = 0; float num2 = farDistance + tile; int num3 = Mathf.FloorToInt((_buildAnchor.x - num2) / tile); int num4 = Mathf.FloorToInt((_buildAnchor.x + num2) / tile); int num5 = Mathf.FloorToInt((_buildAnchor.z - num2) / tile); int num6 = Mathf.FloorToInt((_buildAnchor.z + num2) / tile); for (int i = num5; i <= num6; i++) { for (int j = num3; j <= num4; j++) { float num7 = DistanceToTile(_buildAnchor.x, _buildAnchor.z, j, i, tile); if (num7 <= farDistance + tile && TileInsideWorld(j, i, tile)) { num++; } } } return num; } private int CountForestTileRequestsForBudget(float tile, float endDistance) { if (!_forestContinuityEnabled.Value) { return 0; } if (!_hasBuildAnchor || _provider == null || !_provider.IsReady) { return ApproximateTileRequestBudget(endDistance, tile); } int num = 0; float num2 = endDistance + tile; int num3 = Mathf.FloorToInt((_buildAnchor.x - num2) / tile); int num4 = Mathf.FloorToInt((_buildAnchor.x + num2) / tile); int num5 = Mathf.FloorToInt((_buildAnchor.z - num2) / tile); int num6 = Mathf.FloorToInt((_buildAnchor.z + num2) / tile); float num7 = Mathf.Max(0f, ContinuityStart() - tile); for (int i = num5; i <= num6; i++) { for (int j = num3; j <= num4; j++) { float num8 = DistanceToTile(_buildAnchor.x, _buildAnchor.z, j, i, tile); if (num8 <= endDistance + tile && num8 >= num7 && TileInsideWorld(j, i, tile)) { num++; } } } return num; } private static int ApproximateTileRequestBudget(float range, float tile) { if (range <= 0f || tile <= 0f) { return 0; } float num = range + tile; return Mathf.CeilToInt(MathF.PI * num * num / Mathf.Max(1f, tile * tile)) + 32; } private float NativeExclusionRadius() { return Mathf.Max(_minimumNearWorldExclusionRadius.Value, _nativeEnvelopeRadius); } private float VisualExclusionRadius() { return Mathf.Max(NativeExclusionRadius(), _innerTerrainDistance.Value); } private bool OutsideExclusion(Vector3 worldPosition, float margin) { //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) return OutsideExclusion(worldPosition.x, worldPosition.z, margin); } private bool OutsideExclusion(float worldX, float worldZ, float margin) { return FlatDistance(worldX, worldZ, _buildAnchor.x, _buildAnchor.z) >= VisualExclusionRadius() + Mathf.Max(0f, margin); } private bool OutsideForestExclusion(float worldX, float worldZ, float margin) { float num = ContinuityStart(); float num2 = ForestExclusionMarginScale(); return FlatDistance(worldX, worldZ, _buildAnchor.x, _buildAnchor.z) >= num + Mathf.Max(0f, margin) * num2; } private bool CardEdgeOutsideForestExclusion(float worldX, float worldZ, float footprintWidthOrRadius) { float num = Mathf.Max(0f, footprintWidthOrRadius) * 0.5f; float num2 = FlatDistance(worldX, worldZ, _buildAnchor.x, _buildAnchor.z) - num; return num2 >= ContinuityStart(); } private void ResetGroundGateCounters() { _placementValidationEpoch++; if (_placementValidationEpoch <= 0) { _placementValidationEpoch = 1; } _nextPlacementValidationId = 0L; _blackForestAtlasSelectionRejected = 0L; _cardsBlockedByMeshLimit = 0L; _groundTransformOk = true; _groundTransformDetail = "pending chunk-local post-mesh verification"; _maxFinalWorldHeightmapError = 0f; _groundGateRejectedCards = 0L; _groundGateRejectedWater = 0L; _groundGateRejectedUnsupported = 0L; _groundGateRejectedHeightMismatch = 0L; _groundGateRejectedProxy = 0L; _coastalLandRecoverySearches = 0L; _coastalLandRecoveryAccepted = 0L; _coastalFoliageOverhangPlacementsAccepted = 0L; _fullResolutionTerrainTilesBuilt = 0; _swampCandidates = 0L; _swampAccepted = 0L; _mountainCandidates = 0L; _mountainAccepted = 0L; _plainsCandidates = 0L; _plainsAccepted = 0L; _mixedCandidates = 0L; _groundLockLowered = 0L; _groundLockRejectedFloat = 0L; _groundLockRejectedDistantUnsupported = 0L; _groundLockRejectedProxy = 0L; _groundLockRejectedCanopy = 0L; _groundLockRejectedTree = 0L; _noFloatPlacementsAttempted = 0L; _noFloatPlacementsAccepted = 0L; _noFloatRejectedBelowWater = 0L; _noFloatRejectedVisibleLandRatio = 0L; _noFloatRejectedCoastlineEdge = 0L; _noFloatRejectedUncertainSupport = 0L; _noFloatRejectedFinalFloating = 0L; _noFloatCardsSunkIntoGround = 0L; _postLockLiftDetectedCount = 0L; _noFloatRejectedTreeBiome = 0L; _noFloatRejectedCanopy = 0L; _noFloatRejectedProxyMass = 0L; _noFloatRejectedFillDuplicate = 0L; _treeBiomeNoFloatAttempts = 0L; _treeBiomeNoFloatValidated = 0L; _treeBiomeRejectedNoFloating = 0L; _treeBiomeRejectedValidationMissing = 0L; _treeBiomeRejectedBelowWater = 0L; _treeBiomeRejectedVisibleLandRatio = 0L; _treeBiomeRejectedAfterMeshGuard = 0L; _addAtlasCardBlockedCount = 0L; _postValidationLiftBlockedCount = 0L; _rootAnchorAttempts = 0L; _rootAnchorAccepted = 0L; _rootAnchorRejectedWater = 0L; _rootAnchorRejectedUnsupported = 0L; _rootAnchorRejectedDryRatio = 0L; _rootAnchorRejectedFloatHeight = 0L; _rootAnchorRejectedWaterChannel = 0L; _closeSwampRejectedWater = 0L; _closeSwampRejectedRoot = 0L; _closeSwampEmitted = 0L; _swampNoFloatAttempts = 0L; _swampPassedDensity = 0L; _swampRejectedThreshold = 0L; _swampRejectedSlope = 0L; _swampRejectedWater = 0L; _swampRejectedVisibleLandRatio = 0L; _swampRejectedCoastline = 0L; _swampRejectedSupport = 0L; _swampRejectedRootAnchor = 0L; _swampRejectedRootDryRatio = 0L; _swampRejectedWaterChannel = 0L; _swampRejectedFinalFloating = 0L; _swampChunksBuilt = 0; _swampRenderersCreated = 0; _proxyAttempts = 0L; _proxyAttemptsBlockedDisabled = 0L; _proxyAttemptsBlockedSwamp = 0L; _treeSampleRetriesUsed = 0L; _lastNoFloatRejectReason = GroundRejectReason.None; _rootAnchorMissingValidationBlocked = 0L; _swampRootAccepted = 0L; _swampRootRejected = 0L; _mountainRootAccepted = 0L; _mountainRootRejected = 0L; _plainsRootAccepted = 0L; _plainsRootRejected = 0L; _mixedRootAccepted = 0L; _mixedRootRejected = 0L; _treeCardMeshGuardBlockedRootMissing = 0L; _treeCardMeshBottomCorrected = 0L; _treeCardPostRootLiftBlocked = 0L; _debugCardBaseLogsThisRebuild = 0; _handoffFillBandCandidatesSeen = 0L; _handoffFillBandCandidatesForced = 0L; _handoffFillBandCandidatesFilled = 0L; _handoffFillBandGapViolations = 0L; _handoffFillBandCandidatesSkippedByChance = 0L; _handoffFillLargestObservedGap = 0f; _handoffFillLastRowAcceptedX = float.NaN; _handoffFillLastRowZ = float.NaN; ResetHandoffTrace(); } private void ResetHandoffTrace() { _traceNearestRawCandidateDistance = float.MaxValue; _traceNearestExclusionRejectedDistance = float.MaxValue; _traceNearestGroundingRejectedDistance = float.MaxValue; _traceNearestBiomeRejectedDistance = float.MaxValue; _traceNearestAcceptedCardDistance = float.MaxValue; _traceLastResetRealtime = Time.realtimeSinceStartup; } private void MaybeRollHandoffTraceWindow() { if (_traceLastResetRealtime < 0f || Time.realtimeSinceStartup - _traceLastResetRealtime > 2f) { ResetHandoffTrace(); } } private bool ValidateAndLockCardToVisibleGround(Biome biome, float x, float z, float footprintWidthOrRadius, float visualHeight, float distance, ForestPlacementKind kind, out PlacementValidationResult validation) { //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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_0672: Unknown result type (might be due to invalid IL or missing references) //IL_06a3: Unknown result type (might be due to invalid IL or missing references) //IL_06a8: Unknown result type (might be due to invalid IL or missing references) //IL_06b7: Unknown result type (might be due to invalid IL or missing references) //IL_06bc: Unknown result type (might be due to invalid IL or missing references) //IL_06ca: Unknown result type (might be due to invalid IL or missing references) //IL_06cf: Unknown result type (might be due to invalid IL or missing references) //IL_06dd: Unknown result type (might be due to invalid IL or missing references) //IL_06e2: Unknown result type (might be due to invalid IL or missing references) //IL_06f1: Unknown result type (might be due to invalid IL or missing references) //IL_06f6: Unknown result type (might be due to invalid IL or missing references) //IL_0703: Unknown result type (might be due to invalid IL or missing references) //IL_0708: Unknown result type (might be due to invalid IL or missing references) //IL_0714: Unknown result type (might be due to invalid IL or missing references) //IL_0719: Unknown result type (might be due to invalid IL or missing references) //IL_0725: Unknown result type (might be due to invalid IL or missing references) //IL_072a: Unknown result type (might be due to invalid IL or missing references) //IL_0735: Unknown result type (might be due to invalid IL or missing references) //IL_073a: Unknown result type (might be due to invalid IL or missing references) //IL_053c: Unknown result type (might be due to invalid IL or missing references) //IL_075b: Unknown result type (might be due to invalid IL or missing references) //IL_0857: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) //IL_0415: Unknown result type (might be due to invalid IL or missing references) //IL_05e9: Unknown result type (might be due to invalid IL or missing references) //IL_07e7: Unknown result type (might be due to invalid IL or missing references) //IL_0652: Unknown result type (might be due to invalid IL or missing references) //IL_090b: Unknown result type (might be due to invalid IL or missing references) //IL_0927: Unknown result type (might be due to invalid IL or missing references) //IL_0932: Unknown result type (might be due to invalid IL or missing references) //IL_094b: Unknown result type (might be due to invalid IL or missing references) //IL_09a6: Unknown result type (might be due to invalid IL or missing references) //IL_09be: Unknown result type (might be due to invalid IL or missing references) //IL_0a91: Unknown result type (might be due to invalid IL or missing references) //IL_0b7b: Unknown result type (might be due to invalid IL or missing references) //IL_0b91: Unknown result type (might be due to invalid IL or missing references) //IL_0af0: Unknown result type (might be due to invalid IL or missing references) //IL_0b0a: Unknown result type (might be due to invalid IL or missing references) //IL_0acc: Unknown result type (might be due to invalid IL or missing references) _forestFootprintChecksThisFrame++; validation = PlacementValidationResult.Invalid(kind, GroundRejectReason.UncertainSupport); _lastValidationBiome = biome; _noFloatPlacementsAttempted++; if (IsTreeBiomeKind(kind)) { _treeBiomeNoFloatAttempts++; } if (IsSwampBiome(biome)) { _swampNoFloatAttempts++; } if (!_groundAuthoritativePlacement.Value && !_enableVisibleLandSupportGate.Value && !_enableCardGroundLock.Value) { if (_provider != null && _provider.TrySample(x, z, out var sample) && sample.Valid && !sample.IsWaterOrOcean) { validation = CreateValidPlacementValidation(kind, biome, x, z, footprintWidthOrRadius, visualHeight, distance, sample.GroundY); _noFloatPlacementsAccepted++; if (IsTreeBiomeKind(kind)) { _treeBiomeNoFloatValidated++; } return true; } return RejectNoFloatingPlacement(kind, GroundRejectReason.UncertainSupport, out validation); } if (_provider == null || !_provider.IsReady) { return RejectNoFloatingPlacement(kind, GroundRejectReason.UncertainSupport, out validation); } if (!TryGetWaterLevel(out var waterLevel)) { if (_failClosedIfSupportUncertain.Value || _rejectIfTerrainSupportUncertain.Value) { return RejectNoFloatingPlacement(kind, GroundRejectReason.UncertainSupport, out validation); } waterLevel = 0f; } float num = DetailedTreeCoastalSafetyWidth(footprintWidthOrRadius, biome, kind); float num2 = Mathf.Max(0.5f, num * 0.5f); float num3 = num2 * 0.70710677f; List list = new List { Vector2.zero, new Vector2(0f - num2, 0f), new Vector2(num2, 0f), new Vector2(0f, num2), new Vector2(0f, 0f - num2), new Vector2(0f - num3, 0f - num3), new Vector2(0f - num3, num3), new Vector2(num3, 0f - num3), new Vector2(num3, num3) }; float num4 = ((_maximumUnsupportedSpan != null) ? Mathf.Max(0.25f, _maximumUnsupportedSpan.Value) : 1.5f); int num5 = Mathf.Max(1, Mathf.CeilToInt(num2 * 2f / num4)); for (int i = 1; i < num5; i++) { float num6 = Mathf.Lerp(0f - num2, num2, (float)i / (float)num5); list.Add(new Vector2(num6, 0f)); list.Add(new Vector2(0f, num6)); float num7 = num6 * 0.70710677f; list.Add(new Vector2(num7, num7)); list.Add(new Vector2(num7, 0f - num7)); } Vector2[] array = list.ToArray(); VisibleGroundSupportSample[] array2 = new VisibleGroundSupportSample[array.Length]; float[] array3 = new float[array.Length]; int num8 = 0; int num9 = 0; int num10 = 0; int num11 = 0; float num12 = float.MaxValue; float num13 = float.MinValue; bool flag = false; for (int j = 0; j < array.Length; j++) { float x2 = x + array[j].x; float z2 = z + array[j].y; if (!TryBuildVisibleGroundSupportSample(biome, x2, z2, distance, waterLevel, out var support)) { return RejectNoFloatingPlacement(kind, GroundRejectReason.UncertainSupport, out validation); } array2[j] = support; if (IsSwampBiome(support.Surface.Biome)) { num11++; } if (RequiresExactVisibleLandSupport(distance) && !support.ExactSupport) { return RejectNoFloatingPlacement(kind, GroundRejectReason.UncertainSupport, out validation); } if (j == 0) { if (IsSwampBiome(biome) && !IsSwampBiome(support.Surface.Biome)) { _swampWrongBiomeRejections++; return RejectNoFloatingPlacement(kind, GroundRejectReason.Unsupported, out validation); } if (_rejectCardsBelowWaterSurface.Value && !support.AboveVisibleWater) { return RejectNoFloatingPlacement(kind, GroundRejectReason.BelowWater, out validation); } if (_rejectOpenWaterCards.Value && support.OpenWater) { return RejectNoFloatingPlacement(kind, GroundRejectReason.BelowWater, out validation); } if (IsSwampBiome(biome) && _enableSwampTreeCards.Value && _swampAllowShallowWetGround.Value && support.Surface.GroundY < waterLevel - _swampMaxShallowWaterDepth.Value) { return RejectNoFloatingPlacement(kind, GroundRejectReason.BelowWater, out validation); } } if (support.WaterCovered) { num10++; flag = true; if (_rejectAnyFootprintSampleWater == null || _rejectAnyFootprintSampleWater.Value) { return RejectNoFloatingPlacement(kind, GroundRejectReason.Water, out validation); } } if (support.VisibleLand) { num9++; array3[num8++] = support.Surface.GroundY; num12 = Mathf.Min(num12, support.Surface.GroundY); num13 = Mathf.Max(num13, support.Surface.GroundY); } } if (_enableVisibleLandSupportGate.Value) { int num14 = Mathf.Clamp(_minimumVisibleLandSamples.Value, 1, array.Length); if (num9 < num14) { return RejectNoFloatingPlacement(kind, GroundRejectReason.VisibleLandRatio, out validation); } float num15 = (float)num9 / (float)array.Length; float num16 = ((!IsSwampBiome(biome)) ? Mathf.Max(Mathf.Clamp01(_requiredVisibleLandSampleRatio.Value), (_minimumFootprintSupportRatio != null) ? Mathf.Clamp01(_minimumFootprintSupportRatio.Value) : 0.7f) : ((_minimumSwampFootprintSupportRatio != null) ? Mathf.Clamp01(_minimumSwampFootprintSupportRatio.Value) : 0.65f)); if (_rejectCoastlineEdgeFloaters.Value && (flag || num10 > 0)) { num16 = Mathf.Max(num16, Mathf.Clamp01(_coastlineVisibleLandSampleRatio.Value)); } if (num15 + 0.0001f < num16) { return RejectNoFloatingPlacement(kind, flag ? GroundRejectReason.CoastlineEdge : GroundRejectReason.VisibleLandRatio, out validation); } if (IsSwampBiome(biome)) { float num17 = (float)num11 / (float)array.Length; float num18 = ((_minimumSwampBiomeFootprintRatio != null) ? Mathf.Clamp01(_minimumSwampBiomeFootprintRatio.Value) : 0.7f); if (num17 + 0.0001f < num18) { _swampWrongBiomeRejections++; return RejectNoFloatingPlacement(kind, GroundRejectReason.Unsupported, out validation); } } if (_rejectIfWaterBetweenSamples.Value && HasWaterBetweenFootprintSamples(biome, x, z, array, distance, waterLevel, out var reason)) { return RejectNoFloatingPlacement(kind, reason, out validation); } } float num19 = GroundSupportWidth(footprintWidthOrRadius, biome, kind); float num20 = Mathf.Max(0.35f, num19 * 0.5f); float num21 = num20 * 0.70710677f; Vector2[] array4 = (Vector2[])(object)new Vector2[9] { Vector2.zero, new Vector2(0f - num20, 0f), new Vector2(num20, 0f), new Vector2(0f, num20), new Vector2(0f, 0f - num20), new Vector2(0f - num21, 0f - num21), new Vector2(0f - num21, num21), new Vector2(num21, 0f - num21), new Vector2(num21, num21) }; num8 = 0; num12 = float.MaxValue; num13 = float.MinValue; for (int k = 0; k < array4.Length; k++) { if (!TryBuildVisibleGroundSupportSample(biome, x + array4[k].x, z + array4[k].y, distance, waterLevel, out var support2)) { return RejectNoFloatingPlacement(kind, GroundRejectReason.UncertainSupport, out validation); } if (RequiresExactVisibleLandSupport(distance) && !support2.ExactSupport) { return RejectNoFloatingPlacement(kind, GroundRejectReason.UncertainSupport, out validation); } if (!support2.VisibleLand || support2.WaterCovered || support2.OpenWater) { return RejectNoFloatingPlacement(kind, GroundRejectReason.Water, out validation); } if (support2.Surface.SlopeDegrees >= BiomeMaxSlope(biome)) { return RejectNoFloatingPlacement(kind, GroundRejectReason.HeightMismatch, out validation); } array3[num8++] = support2.Surface.GroundY; num12 = Mathf.Min(num12, support2.Surface.GroundY); num13 = Mathf.Max(num13, support2.Surface.GroundY); } float num22 = (float)num8 / (float)array4.Length; float num23 = ((!IsSwampBiome(biome)) ? ((_minimumRootSupportRatio != null) ? Mathf.Clamp01(_minimumRootSupportRatio.Value) : 0.8f) : ((_minimumSwampRootSupportRatio != null) ? Mathf.Clamp01(_minimumSwampRootSupportRatio.Value) : 0.75f)); if (num8 <= 0 || num22 + 0.0001f < num23) { return RejectNoFloatingPlacement(kind, GroundRejectReason.Unsupported, out validation); } float num24 = ((!(num19 > 10f)) ? ((_maxGroundHeightVarianceStandardCard != null) ? _maxGroundHeightVarianceStandardCard.Value : 1.5f) : ((_maxGroundHeightVarianceLargeCard != null) ? _maxGroundHeightVarianceLargeCard.Value : 0.75f)); if (num13 - num12 > Mathf.Min(MaxFootprintHeightDiffForBiome(biome), num24)) { return RejectNoFloatingPlacement(kind, GroundRejectReason.HeightMismatch, out validation); } float num25 = DetailedTreeCoastalNearWaterRadius(biome, kind); float minimumAboveWater = DetailedTreeCoastalMinimumAboveWater(biome, kind); if (num25 > 0.01f && HasUnsafeWaterNearFootprint(x, z, num25, waterLevel, biome, minimumAboveWater, out var reason2)) { return RejectNoFloatingPlacement(kind, (reason2 == GroundRejectReason.Unsupported) ? GroundRejectReason.UncertainSupport : GroundRejectReason.CoastlineEdge, out validation); } bool flag2 = GroundLockApplies(kind); float num26 = (flag2 ? SupportedBaseHeight(array3, num8, _cardBaseHeightMode.Value) : array2[0].Surface.GroundY); bool flag3 = RootAnchorApplies(kind, biome); float num27 = ((flag2 && !flag3) ? BiomeSinkIntoGround(biome) : 0f); if (num27 > 0f) { num26 -= num27; _noFloatCardsSunkIntoGround++; } float groundY = array2[0].Surface.GroundY; float num28 = num12 + _maxCardBaseAboveGround.Value; if (flag2 && num26 > num28) { if (_rejectIfFinalBaseFloats.Value && num26 > num12 + _finalBaseFloatTolerance.Value) { return RejectNoFloatingPlacement(kind, GroundRejectReason.FinalFloating, out validation); } num26 = num28; _groundLockLowered++; } if (_rejectIfFinalBaseFloats.Value && (num26 > num12 + _finalBaseFloatTolerance.Value || num26 > groundY + _finalBaseFloatTolerance.Value)) { return RejectNoFloatingPlacement(kind, GroundRejectReason.FinalFloating, out validation); } bool flag4 = IsAllowedShallowSwampSupport(biome, array2[0].Surface, waterLevel); if (_rejectCardsBelowWaterSurface.Value && !flag4 && array2[0].Surface.GroundY < waterLevel + MinimumBaseAboveWaterForBiome(biome)) { return RejectNoFloatingPlacement(kind, GroundRejectReason.BelowWater, out validation); } float num29 = 0f; if (flag2) { num29 = VerticalAdjustmentForBiome(biome); num26 += num29; _lastAppliedVerticalAdjustment = num29; bool rootAnchorValidated = RootAnchorApplies(kind, biome); _lastFinalVisibleRootY = ResolveFinalVisibleRootY(num26, rootAnchorValidated, IsGroundLevelCardKind(kind)); float num30 = ResolveFinalVisibleRootY(array2[0].Surface.GroundY + num29, rootAnchorValidated, IsGroundLevelCardKind(kind)); _lastFinalVisibleRootError = _lastFinalVisibleRootY - num30; if (num29 < 0f) { _cardsCorrectedDownward++; } } validation = CreateValidPlacementValidation(kind, biome, x, z, footprintWidthOrRadius, visualHeight, distance, num26); if (AllowsDetailedTreeCoastalOverhang(biome, kind) && num + 0.01f < footprintWidthOrRadius) { _coastalFoliageOverhangPlacementsAccepted++; } _noFloatPlacementsAccepted++; if (IsTreeBiomeKind(kind)) { _treeBiomeNoFloatValidated++; } return true; } private bool TryBuildVisibleGroundSupportSample(Biome cardBiome, float x, float z, float distance, float waterLevel, out VisibleGroundSupportSample support) { //IL_0088: 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_009f: 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) support = default(VisibleGroundSupportSample); _forestTerrainSamplesThisFrame++; if (_provider == null || !_provider.TrySample(x, z, out var sample) || !sample.Valid) { return false; } if (TryResolveRenderedGroundY(x, z, distance, sample.GroundY, out var groundY, out var source)) { sample.GroundY = groundY; _lastGroundedRenderedSource = source; _lastRenderedGroundY = groundY; } support.Surface = sample; support.WaterHeight = waterLevel; support.ExactSupport = HasExactTerrainSupportAt(x, z, distance); bool flag = IsAllowedShallowSwampSupport(cardBiome, sample, waterLevel); support.OpenWater = (sample.Biome & 0x100) != 0 || (sample.GroundY <= waterLevel && !flag); float num = MinimumBaseAboveWaterForBiome(cardBiome); support.AboveVisibleWater = !support.OpenWater && (flag || sample.GroundY >= waterLevel + num); support.WaterCovered = support.OpenWater || (!flag && ((_rejectCardsBelowWaterSurface.Value && !support.AboveVisibleWater) || (_rejectOpenWaterCards.Value && sample.IsWaterOrOcean))); support.VisibleLand = support.ExactSupport && support.AboveVisibleWater && !support.WaterCovered; return true; } private bool IsAllowedShallowSwampSupport(Biome cardBiome, WorldSurfaceSample surface, float waterLevel) { //IL_0000: 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_002b: 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) if (IsSwampBiome(cardBiome) && IsSwampBiome(surface.Biome) && _swampAllowShallowWetGround != null && _swampAllowShallowWetGround.Value && (surface.Biome & 0x100) == 0) { return surface.GroundY >= waterLevel - ((_swampMaxShallowWaterDepth != null) ? _swampMaxShallowWaterDepth.Value : 0.2f); } return false; } private bool CandidateSurfaceSupported(WorldSurfaceSample surface) { //IL_0009: 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_002e: Unknown result type (might be due to invalid IL or missing references) if (!surface.Valid || (surface.Biome & 0x100) != 0) { return false; } if (!surface.IsWaterOrOcean) { return true; } if (TryGetWaterLevel(out var waterLevel)) { return IsAllowedShallowSwampSupport(surface.Biome, surface, waterLevel); } return false; } private PlacementValidationResult CreateValidPlacementValidation(ForestPlacementKind kind, Biome biome, float x, float z, float width, float height, float distance, float finalBaseY) { //IL_000b: 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) PlacementValidationResult result = PlacementValidationResult.Valid(kind, finalBaseY); result.ValidatedBiome = biome; result.ValidatedCenterX = x; result.ValidatedCenterZ = z; result.ValidatedWidth = width; result.ValidatedHeight = height; result.ValidatedDistance = distance; result.ValidationEpoch = _placementValidationEpoch; result.ValidationId = ++_nextPlacementValidationId; return result; } private bool RootAnchorApplies(ForestPlacementKind kind, Biome biome) { //IL_003c: 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_0064: Unknown result type (might be due to invalid IL or missing references) if (_enableTrunkAnchorGrounding == null || !_enableTrunkAnchorGrounding.Value) { return false; } switch (kind) { case ForestPlacementKind.FillCard: return _applyRootToFillTreeCards.Value; case ForestPlacementKind.TreeCard: return _applyRootToMixedTreeCards.Value; default: return false; case ForestPlacementKind.BiomeCard: if (IsSwampBiome(biome)) { return _applyRootToSwampTreeCards.Value; } if (IsMountainBiomeB(biome)) { return _applyRootToMountainTreeCards.Value; } if (IsPlainsBiomeB(biome)) { return _applyRootToPlainsTreeCards.Value; } return _applyRootToMixedTreeCards.Value; } } private bool ValidateAndLockTrunkAnchor(ref PlacementValidationResult validation, Biome biome, float x, float z, float width, float height, float angle, float distance, ForestPlacementKind kind) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_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_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0142: 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_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: 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_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017d: 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_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_03f7: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Unknown result type (might be due to invalid IL or missing references) //IL_042e: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_048f: Unknown result type (might be due to invalid IL or missing references) //IL_0442: Unknown result type (might be due to invalid IL or missing references) //IL_04dd: Unknown result type (might be due to invalid IL or missing references) //IL_0514: Unknown result type (might be due to invalid IL or missing references) //IL_051c: Unknown result type (might be due to invalid IL or missing references) //IL_0522: Unknown result type (might be due to invalid IL or missing references) //IL_0527: Unknown result type (might be due to invalid IL or missing references) //IL_05a5: Unknown result type (might be due to invalid IL or missing references) //IL_05da: Unknown result type (might be due to invalid IL or missing references) _rootAnchorAttempts++; if (!validation.IsValid || validation.ValidationEpoch != _placementValidationEpoch || validation.ValidationId <= 0) { RootAnchorRejectReason reason = ((validation.ValidationEpoch != _placementValidationEpoch) ? RootAnchorRejectReason.StaleValidation : RootAnchorRejectReason.MissingValidation); return RejectRootAnchor(ref validation, biome, reason, 0f); } if (!IsPlacementValidationCurrentAndMatching(validation, x, z, width, height, kind) || validation.ValidatedBiome != biome) { return RejectRootAnchor(ref validation, biome, RootAnchorRejectReason.MismatchedValidation, 0f); } if (!TryGetWaterLevel(out var waterLevel)) { return RejectRootAnchor(ref validation, biome, RootAnchorRejectReason.Unsupported, 0f); } Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(Mathf.Cos(angle), Mathf.Sin(angle)); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0f - val.y, val.x); Vector2 val3 = new Vector2(x, z) + val2 * _rootAnchorForwardOffset.Value + val * _rootAnchorSideOffset.Value; float num = Mathf.Max(0.1f, _rootAnchorSampleRadius.Value); float num2 = num * 0.70710677f; Vector2[] array = (Vector2[])(object)((!_rootAnchorExtraSamples.Value) ? new Vector2[5] { Vector2.zero, val2 * num, val2 * (0f - num), val * (0f - num), val * num } : new Vector2[9] { Vector2.zero, val2 * num, val2 * (0f - num), val * (0f - num), val * num, (val2 + val) * num2, (val2 - val) * num2, (-val2 + val) * num2, (-val2 - val) * num2 }); bool flag = RequiresExactVisibleLandSupport(distance); float num3 = RootMinimumBaseAboveWaterForBiome(biome); int num4 = 0; int num5 = 0; float num6 = 0f; float num7 = float.MaxValue; bool flag2 = false; for (int i = 0; i < array.Length; i++) { if (!TryBuildVisibleGroundSupportSample(biome, val3.x + array[i].x, val3.y + array[i].y, distance, waterLevel, out var support)) { if (i == 0 || _rejectIfRootAnchorUnsupported.Value || _failClosedIfSupportUncertain.Value) { return RejectRootAnchor(ref validation, biome, RootAnchorRejectReason.Unsupported, (float)num5 / (float)array.Length); } continue; } if (flag && !support.ExactSupport) { return RejectRootAnchor(ref validation, biome, RootAnchorRejectReason.Unsupported, (float)num5 / (float)array.Length); } num4++; if (!IsAllowedShallowSwampSupport(biome, support.Surface, waterLevel) && (support.OpenWater || support.Surface.IsWaterOrOcean || support.Surface.GroundY < waterLevel + num3)) { if (i == 0 || _rejectIfRootAnchorBelowWater.Value) { return RejectRootAnchor(ref validation, biome, RootAnchorRejectReason.Water, (float)num5 / (float)array.Length); } continue; } num5++; num7 = Mathf.Min(num7, support.Surface.GroundY); if (i == 0) { flag2 = true; num6 = support.Surface.GroundY; } } float num8 = (float)num5 / (float)array.Length; int num9 = Mathf.Clamp(_rootAnchorMinimumSamples.Value, 1, array.Length); float num10 = RootAnchorRequiredDryRatioForBiome(biome); if (!flag2 || num4 < num9) { return RejectRootAnchor(ref validation, biome, RootAnchorRejectReason.Unsupported, num8); } if (num5 < num9 || num8 + 0.0001f < num10) { return RejectRootAnchor(ref validation, biome, RootAnchorRejectReason.DryRatio, num8); } if ((_rejectIfRootAnchorOverWaterChannel.Value || (IsSwampBiome(biome) && _swampRejectRootNearOpenWater.Value)) && HasUnsafeRootWaterChannel(biome, val3, val, val2, distance, waterLevel, num3, out var reason2)) { return RejectRootAnchor(ref validation, biome, reason2, num8); } float num11 = Mathf.Min(num6, num7); float num12 = validation.FinalBaseY - num11; if (num12 > _rootAnchorFloatTolerance.Value + 0.0001f || num12 > _rootAnchorMaximumAboveGround.Value + 0.0001f) { return RejectRootAnchor(ref validation, biome, RootAnchorRejectReason.FloatHeight, num8); } float finalBaseY = validation.FinalBaseY; float num13 = Mathf.Min(finalBaseY, num11); if (num13 < validation.FinalBaseY - 0.0001f) { _groundLockLowered++; } float num14 = (GroundLockApplies(kind) ? BiomeSinkIntoGround(biome) : 0f); if (num14 > 0f) { num13 -= num14; _noFloatCardsSunkIntoGround++; } validation.FinalBaseY = num13; validation.RootAnchorValidated = true; validation.RootAnchorWorldPosition = new Vector3(val3.x, num13, val3.y); validation.RootAnchorGroundY = num6; validation.RootAnchorWaterY = waterLevel; validation.RootAnchorDrySampleRatio = num8; validation.RootAnchorRejectReason = RootAnchorRejectReason.None; validation.RootAnchorAngle = angle; validation.RootAnchorMode = _rootAnchorMode.Value; validation.RootPreLockBaseY = finalBaseY; validation.RootLockedBaseY = num13; validation.RootAnchorValidationEpoch = _placementValidationEpoch; validation.RootAnchorValidationId = validation.ValidationId; _lastFinalVisibleRootY = ResolveFinalVisibleRootY(num13, rootAnchorValidated: true, IsGroundLevelCardKind(kind)); float num15 = ResolveFinalVisibleRootY(num11 + VerticalAdjustmentForBiome(biome), rootAnchorValidated: true, IsGroundLevelCardKind(kind)); _lastFinalVisibleRootError = _lastFinalVisibleRootY - num15; _rootAnchorAccepted++; RegisterRootBiomeOutcome(biome, accepted: true); return true; } private bool HasUnsafeRootWaterChannel(Biome biome, Vector2 root, Vector2 right, Vector2 forward, float distance, float waterLevel, float minimumAboveWater, out RootAnchorRejectReason reason) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0079: 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_0087: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_00ea: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0146: 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_01af: Unknown result type (might be due to invalid IL or missing references) reason = RootAnchorRejectReason.None; float num = Mathf.Max(0.1f, _rootAnchorSampleRadius.Value); if (IsSwampBiome(biome) && _swampRejectRootNearOpenWater.Value) { num = Mathf.Max(num, _swampRootWaterChannelProbeRadius.Value); } float num2 = num * 0.5f; float num3 = num * 0.70710677f; Vector2[] array = (Vector2[])(object)new Vector2[12] { forward * num2, forward * (0f - num2), right * num2, right * (0f - num2), forward * num, forward * (0f - num), right * num, right * (0f - num), (forward + right) * num3, (forward - right) * num3, (-forward + right) * num3, (-forward - right) * num3 }; bool flag = RequiresExactVisibleLandSupport(distance); for (int i = 0; i < array.Length; i++) { if (!TryBuildVisibleGroundSupportSample(biome, root.x + array[i].x, root.y + array[i].y, distance, waterLevel, out var support)) { if (_rejectIfRootAnchorUnsupported.Value || _failClosedIfSupportUncertain.Value) { reason = RootAnchorRejectReason.Unsupported; return true; } continue; } if (flag && !support.ExactSupport) { reason = RootAnchorRejectReason.Unsupported; return true; } if (!IsAllowedShallowSwampSupport(biome, support.Surface, waterLevel) && (support.OpenWater || support.Surface.IsWaterOrOcean || support.Surface.GroundY < waterLevel + minimumAboveWater)) { reason = RootAnchorRejectReason.WaterChannel; return true; } } return false; } private float RootMinimumBaseAboveWaterForBiome(Biome biome) { //IL_0000: 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_0009: Unknown result type (might be due to invalid IL or missing references) if (IsSwampBiome(biome)) { return Mathf.Max(MinimumBaseAboveWaterForBiome(biome), _swampRootAnchorMinimumBaseAboveWater.Value); } return MinimumBaseAboveWaterForBiome(biome); } private float RootAnchorRequiredDryRatioForBiome(Biome biome) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) float result = Mathf.Max((_rootAnchorRequiredDryRatio != null) ? Mathf.Clamp01(_rootAnchorRequiredDryRatio.Value) : 0.8f, (_minimumRootSupportRatio != null) ? Mathf.Clamp01(_minimumRootSupportRatio.Value) : 0.8f); if (IsSwampBiome(biome)) { result = Mathf.Max((_swampRootAnchorRequiredDryRatio != null) ? Mathf.Clamp01(_swampRootAnchorRequiredDryRatio.Value) : 0.75f, (_minimumSwampRootSupportRatio != null) ? Mathf.Clamp01(_minimumSwampRootSupportRatio.Value) : 0.75f); } return result; } private bool RejectRootAnchor(ref PlacementValidationResult validation, Biome biome, RootAnchorRejectReason reason, float dryRatio) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) validation.IsValid = false; validation.RootAnchorValidated = false; validation.RootAnchorDrySampleRatio = Mathf.Clamp01(dryRatio); validation.RootAnchorRejectReason = reason; validation.RejectReason = GroundReasonForRootReject(reason); RegisterRootAnchorReject(reason); RegisterRootBiomeOutcome(biome, accepted: false); if (IsSwampBiome(biome)) { _swampRejectedRootAnchor++; switch (reason) { case RootAnchorRejectReason.DryRatio: _swampRejectedRootDryRatio++; break; case RootAnchorRejectReason.WaterChannel: _swampRejectedWaterChannel++; break; } } return false; } private void RegisterRootAnchorReject(RootAnchorRejectReason reason) { switch (reason) { case RootAnchorRejectReason.Water: _rootAnchorRejectedWater++; break; case RootAnchorRejectReason.DryRatio: _rootAnchorRejectedDryRatio++; break; case RootAnchorRejectReason.FloatHeight: _rootAnchorRejectedFloatHeight++; break; case RootAnchorRejectReason.WaterChannel: _rootAnchorRejectedWaterChannel++; break; default: _rootAnchorRejectedUnsupported++; break; } } private void RegisterRootBiomeOutcome(Biome biome, bool accepted) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (IsSwampBiome(biome)) { if (accepted) { _swampRootAccepted++; } else { _swampRootRejected++; } } else if (IsMountainBiomeB(biome)) { if (accepted) { _mountainRootAccepted++; } else { _mountainRootRejected++; } } else if (IsPlainsBiomeB(biome)) { if (accepted) { _plainsRootAccepted++; } else { _plainsRootRejected++; } } else if (accepted) { _mixedRootAccepted++; } else { _mixedRootRejected++; } } private static GroundRejectReason GroundReasonForRootReject(RootAnchorRejectReason reason) { return reason switch { RootAnchorRejectReason.Water => GroundRejectReason.BelowWater, RootAnchorRejectReason.DryRatio => GroundRejectReason.VisibleLandRatio, RootAnchorRejectReason.WaterChannel => GroundRejectReason.CoastlineEdge, RootAnchorRejectReason.FloatHeight => GroundRejectReason.FinalFloating, _ => GroundRejectReason.UncertainSupport, }; } private bool IsPlacementValidationCurrentAndMatching(PlacementValidationResult validation, float x, float z, float width, float height, ForestPlacementKind kind) { if (!validation.IsValid || !validation.GroundLocked || !validation.VisibleLandSupported || validation.CardKind != kind) { return false; } if (validation.ValidationEpoch != _placementValidationEpoch || validation.ValidationId <= 0) { return false; } if (Mathf.Abs(validation.ValidatedCenterX - x) <= 0.001f && Mathf.Abs(validation.ValidatedCenterZ - z) <= 0.001f && Mathf.Abs(validation.ValidatedWidth - width) <= 0.001f) { return Mathf.Abs(validation.ValidatedHeight - height) <= 0.001f; } return false; } private bool HasMatchingRootAnchorProof(PlacementValidationResult validation, float x, float z, float angle) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_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) //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) //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_00d2: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) if (!validation.RootAnchorValidated || validation.RootAnchorRejectReason != RootAnchorRejectReason.None) { return false; } if (validation.RootAnchorValidationEpoch != _placementValidationEpoch || validation.RootAnchorValidationId != validation.ValidationId) { return false; } if (validation.RootAnchorMode != _rootAnchorMode.Value) { return false; } if (Mathf.Abs(validation.FinalBaseY - validation.RootLockedBaseY) > 0.001f) { return false; } if (AngularDifferenceRadians(validation.RootAnchorAngle, angle) > 0.001f) { return false; } Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(Mathf.Cos(angle), Mathf.Sin(angle)); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0f - val.y, val.x); Vector2 val3 = new Vector2(x, z) + val2 * _rootAnchorForwardOffset.Value + val * _rootAnchorSideOffset.Value; if (Mathf.Abs(validation.RootAnchorWorldPosition.x - val3.x) <= 0.001f) { return Mathf.Abs(validation.RootAnchorWorldPosition.z - val3.y) <= 0.001f; } return false; } private void RegisterRootMissingMeshGuardReject(ForestPlacementKind kind) { _rootAnchorMissingValidationBlocked++; _treeCardMeshGuardBlockedRootMissing++; RegisterMeshGuardReject(kind, atlasCard: true, validationMissing: true); } private static float AngularDifferenceRadians(float a, float b) { float num = MathF.PI * 2f; float num2 = Mathf.Abs(a - b) % num; return Mathf.Min(num2, num - num2); } private bool HasWaterBetweenFootprintSamples(Biome biome, float x, float z, Vector2[] offsets, float distance, float waterLevel, out GroundRejectReason reason) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) reason = GroundRejectReason.None; for (int i = 1; i < offsets.Length; i++) { float x2 = x + offsets[i].x * 0.5f; float z2 = z + offsets[i].y * 0.5f; if (!TryBuildVisibleGroundSupportSample(biome, x2, z2, distance, waterLevel, out var support)) { reason = GroundRejectReason.UncertainSupport; return _failClosedIfSupportUncertain.Value; } if (RequiresExactVisibleLandSupport(distance) && !support.ExactSupport) { reason = GroundRejectReason.UncertainSupport; return true; } if (support.WaterCovered || !support.AboveVisibleWater) { reason = GroundRejectReason.CoastlineEdge; return true; } } return false; } private bool GroundLockApplies(ForestPlacementKind kind) { if (!_enableCardGroundLock.Value) { return false; } return kind switch { ForestPlacementKind.ProxyMass => _applyGroundLockToProxyForests.Value, ForestPlacementKind.CanopyCard => _applyGroundLockToCanopyCards.Value, ForestPlacementKind.FillCard => _applyGroundLockToFillCards.Value, ForestPlacementKind.BiomeCard => _applyGroundLockToBiomeCards.Value, _ => _applyGroundLockToTreeCards.Value, }; } private bool RequiresExactVisibleLandSupport(float distance) { if (_failClosedIfSupportUncertain.Value || _rejectIfTerrainSupportUncertain.Value || _rejectAnyFootprintSampleUnsupported.Value) { return true; } if (distance > NativeExclusionRadius() && (_distantCardsRequireExactVisibleLandSupport.Value || _rejectDistantUnsupportedCards.Value)) { return true; } return false; } private float MinimumBaseAboveWaterForBiome(Biome biome) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (IsSwampBiome(biome)) { return Mathf.Max(_swampMinimumBaseAboveWater.Value, _swampMinimumLandAboveWater.Value); } return _minimumBaseAboveWater.Value; } private bool RejectNoFloatingPlacement(ForestPlacementKind kind, GroundRejectReason reason) { _lastNoFloatRejectReason = reason; RegisterNoFloatingReject(kind, reason); return false; } private bool RejectNoFloatingPlacement(ForestPlacementKind kind, GroundRejectReason reason, out PlacementValidationResult validation) { validation = PlacementValidationResult.Invalid(kind, reason); RegisterNoFloatingReject(kind, reason); return false; } private static float SupportedBaseHeight(float[] grounds, int count, CardBaseHeightMode mode) { if (count <= 0) { return 0f; } if (count == 1) { return grounds[0]; } float[] array = new float[count]; Array.Copy(grounds, array, count); Array.Sort(array, 0, count); switch (mode) { case CardBaseHeightMode.LowestSupportedGround: return array[0]; case CardBaseHeightMode.LowerMiddleSupportedGround: return array[Mathf.Clamp(Mathf.FloorToInt((float)count * 0.35f), 0, count - 1)]; default: { int num = count / 2; if (count % 2 != 0) { return array[num]; } return (array[num - 1] + array[num]) * 0.5f; } } } private void RegisterGroundLockRejectByKind(ForestPlacementKind kind) { switch (kind) { case ForestPlacementKind.ProxyMass: _groundLockRejectedProxy++; break; case ForestPlacementKind.CanopyCard: case ForestPlacementKind.FillCard: _groundLockRejectedCanopy++; break; default: _groundLockRejectedTree++; break; } } private void RegisterNoFloatingReject(ForestPlacementKind kind, GroundRejectReason reason) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (IsTreeBiomeKind(kind)) { _treeBiomeRejectedNoFloating++; switch (reason) { case GroundRejectReason.Water: case GroundRejectReason.BelowWater: _treeBiomeRejectedBelowWater++; break; case GroundRejectReason.VisibleLandRatio: case GroundRejectReason.CoastlineEdge: _treeBiomeRejectedVisibleLandRatio++; break; } } if (IsSwampBiome(_lastValidationBiome)) { switch (reason) { case GroundRejectReason.Water: case GroundRejectReason.BelowWater: _swampRejectedWater++; break; case GroundRejectReason.VisibleLandRatio: _swampRejectedVisibleLandRatio++; break; case GroundRejectReason.CoastlineEdge: _swampRejectedCoastline++; break; case GroundRejectReason.Unsupported: case GroundRejectReason.UncertainSupport: _swampRejectedSupport++; break; case GroundRejectReason.FinalFloating: _swampRejectedFinalFloating++; break; } } switch (reason) { case GroundRejectReason.Water: case GroundRejectReason.BelowWater: _noFloatRejectedBelowWater++; break; case GroundRejectReason.VisibleLandRatio: _noFloatRejectedVisibleLandRatio++; break; case GroundRejectReason.CoastlineEdge: _noFloatRejectedCoastlineEdge++; break; case GroundRejectReason.Unsupported: case GroundRejectReason.UncertainSupport: _noFloatRejectedUncertainSupport++; _groundLockRejectedDistantUnsupported++; break; case GroundRejectReason.FinalFloating: _noFloatRejectedFinalFloating++; _groundLockRejectedFloat++; break; } switch (kind) { case ForestPlacementKind.ProxyMass: _noFloatRejectedProxyMass++; break; case ForestPlacementKind.CanopyCard: _noFloatRejectedCanopy++; break; case ForestPlacementKind.FillCard: _noFloatRejectedFillDuplicate++; break; default: _noFloatRejectedTreeBiome++; break; } RegisterGroundLockRejectByKind(kind); RegisterGroundGateReject(kind, CollapseNoFloatingReason(reason)); } private static bool IsTreeBiomeKind(ForestPlacementKind kind) { if (kind != ForestPlacementKind.TreeCard) { return kind == ForestPlacementKind.BiomeCard; } return true; } private static GroundRejectReason CollapseNoFloatingReason(GroundRejectReason reason) { switch (reason) { case GroundRejectReason.BelowWater: case GroundRejectReason.VisibleLandRatio: case GroundRejectReason.CoastlineEdge: return GroundRejectReason.Water; case GroundRejectReason.UncertainSupport: return GroundRejectReason.Unsupported; case GroundRejectReason.FinalFloating: return GroundRejectReason.HeightMismatch; default: return reason; } } private bool HasExactTerrainSupportAt(float worldX, float worldZ, float distance) { if (!_requireExactFootprintTerrainSupport.Value) { return true; } if (distance <= NativeExclusionRadius()) { return true; } if (!_enableFarTerrain.Value) { return false; } float num = FarTerrainTileSize(); int x = Mathf.FloorToInt(worldX / num); int z = Mathf.FloorToInt(worldZ / num); if (_terrainTiles.TryGetValue(TileKey(x, z), out var value) && value != null) { return (Object)(object)value.Mesh != (Object)null; } return false; } private bool TrySampleFarTerrainMeshHeight(float worldX, float worldZ, out float height) { height = 0f; float num = FarTerrainTileSize(); int num2 = Mathf.FloorToInt(worldX / num); int num3 = Mathf.FloorToInt(worldZ / num); if (!_terrainTiles.TryGetValue(TileKey(num2, num3), out var value) || value == null || value.HeightGrid == null || value.GridResolution <= 0) { return false; } int gridResolution = value.GridResolution; int num4 = gridResolution + 1; float num5 = (float)num2 * num; float num6 = (float)num3 * num; float num7 = Mathf.Clamp((worldX - num5) / num * (float)gridResolution, 0f, (float)gridResolution); float num8 = Mathf.Clamp((worldZ - num6) / num * (float)gridResolution, 0f, (float)gridResolution); int num9 = Mathf.Clamp(Mathf.FloorToInt(num7), 0, gridResolution - 1); int num10 = Mathf.Clamp(Mathf.FloorToInt(num8), 0, gridResolution - 1); float num11 = num7 - (float)num9; float num12 = num8 - (float)num10; float[] heightGrid = value.HeightGrid; float num13 = heightGrid[num10 * num4 + num9]; float num14 = heightGrid[num10 * num4 + num9 + 1]; float num15 = heightGrid[(num10 + 1) * num4 + num9]; float num16 = heightGrid[(num10 + 1) * num4 + num9 + 1]; if (num11 + num12 <= 1f) { height = num13 + (num15 - num13) * num12 + (num14 - num13) * num11; } else { height = num14 + (num11 + num12 - 1f) * (num16 - num14) + (1f - num11) * (num15 - num14); } return true; } private bool TryResolveRenderedGroundY(float worldX, float worldZ, float distance, float providerGroundY, out float groundY, out string source) { if (_enableFarTerrain != null && _enableFarTerrain.Value && distance > NativeExclusionRadius()) { if (TrySampleFarTerrainMeshHeight(worldX, worldZ, out var height)) { groundY = height; source = "FarTerrainMesh"; _renderedGroundSourceFarMeshCount++; return true; } groundY = providerGroundY; source = "ProviderFallback"; _renderedGroundSourceProviderFallbackCount++; return true; } groundY = providerGroundY; source = "NativeHeightmap"; _renderedGroundSourceNativeCount++; return true; } private static bool IsMountainBiomeB(Biome biome) { //IL_0000: 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_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if ((biome & 4) == 0) { return (biome & 0x40) > 0; } return true; } private static bool IsPlainsBiomeB(Biome biome) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 return (biome & 0x10) > 0; } private float BiomeCandidateDensityFloor(Biome biome) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_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_0015: 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_0059: Unknown result type (might be due to invalid IL or missing references) if ((biome & 0x20) != 0 || (biome & 0x100) != 0) { return 0f; } if (IsSwampBiome(biome)) { if (!_enableSwampTreeCards.Value) { return 0f; } return SwampCandidateDensityFloor(); } if (IsMountainBiomeB(biome)) { if (!_enableMountainTreeCards.Value) { return 0f; } return MountainCandidateDensityFloor(); } if (IsPlainsBiomeB(biome)) { if (!_enablePlainsSparseTreeCards.Value) { return 0f; } return PlainsCandidateDensityFloor(); } return MixedCandidateDensityFloor(); } private string LegacyBiomeDensitySettingsSummary() { return "Swamp=" + ((_swampTreeDensityMultiplier != null) ? _swampTreeDensityMultiplier.Value.ToString("R", CultureInfo.InvariantCulture) : "n/a") + ", SwampNear=" + ((_swampNearCardDensityMultiplier != null) ? _swampNearCardDensityMultiplier.Value.ToString("R", CultureInfo.InvariantCulture) : "n/a") + ", SwampMid=" + ((_swampMidCardDensityMultiplier != null) ? _swampMidCardDensityMultiplier.Value.ToString("R", CultureInfo.InvariantCulture) : "n/a") + ", Mountain=" + ((_mountainTreeDensityMultiplier != null) ? _mountainTreeDensityMultiplier.Value.ToString("R", CultureInfo.InvariantCulture) : "n/a") + ", Plains=" + ((_plainsTreeDensityMultiplier != null) ? _plainsTreeDensityMultiplier.Value.ToString("R", CultureInfo.InvariantCulture) : "n/a") + " (all ignored)"; } private float BiomeMaxSlope(Biome biome) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (IsMountainBiomeB(biome) && _enableMountainTreeCards.Value) { return _mountainMaximumSlope.Value; } return _hardSlopeRejectionThreshold.Value; } private float FootprintRadiusScale(Biome biome) { //IL_0000: 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) if (IsSwampBiome(biome) && _enableSwampTreeCards.Value) { return _swampFootprintRadiusScale.Value; } if (IsMountainBiomeB(biome) && _enableMountainTreeCards.Value) { return _mountainFootprintRadiusScale.Value; } return 1f; } private float MaxFootprintHeightDiffForBiome(Biome biome) { //IL_0000: 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) if (IsSwampBiome(biome) && _enableSwampTreeCards.Value) { return _swampMaxFootprintHeightDiff.Value; } if (IsMountainBiomeB(biome) && _enableMountainTreeCards.Value) { return _mountainMaxFootprintHeightDiff.Value; } return _maxFootprintHeightDifference.Value; } private float BiomeSinkIntoGround(Biome biome) { //IL_0000: 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) if (IsSwampBiome(biome) && _swampSinkIntoGround != null) { return Mathf.Min(0f, _swampSinkIntoGround.Value); } if (IsMountainBiomeB(biome) && _mountainSinkIntoGround != null) { return Mathf.Min(0f, _mountainSinkIntoGround.Value); } return 0f; } private float VerticalAdjustmentForBiome(Biome biome) { //IL_001b: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) float num = ((_treeCardVerticalAdjustment != null) ? _treeCardVerticalAdjustment.Value : (-0.2f)); float num2 = (IsSwampBiome(biome) ? ((_swampVerticalAdjustmentFinal != null) ? _swampVerticalAdjustmentFinal.Value : 0f) : (IsMountainBiomeB(biome) ? ((_mountainVerticalAdjustmentFinal != null) ? _mountainVerticalAdjustmentFinal.Value : 0f) : (IsPlainsBiomeB(biome) ? ((_plainsVerticalAdjustmentFinal != null) ? _plainsVerticalAdjustmentFinal.Value : 0f) : (((biome & 8) == 0) ? ((_mixedVerticalAdjustment != null) ? _mixedVerticalAdjustment.Value : 0f) : ((_blackForestVerticalAdjustment != null) ? _blackForestVerticalAdjustment.Value : 0f))))); return num + num2; } private float SampleSlopeAwareGroundY(float x, float z, float distance, Biome biome, out bool valid) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) valid = false; if (_provider == null) { return 0f; } if (!_provider.TrySample(x, z, out var sample) || !sample.Valid) { return 0f; } if (sample.IsWaterOrOcean || (sample.Biome & 0x100) != 0) { return 0f; } TryResolveRenderedGroundY(x, z, distance, sample.GroundY, out var groundY, out var _); valid = true; return groundY + VerticalAdjustmentForBiome(biome); } private bool EvaluateVisibleEdgeGrounding(float x, float z, float width, float angle, Biome biome, float bottomY, float distance, bool isMountainCard, out float maxFloatError, out float maxBurialError, out float variation) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) maxFloatError = float.MaxValue; maxBurialError = float.MaxValue; variation = float.MaxValue; if (_provider == null) { return false; } float num = Mathf.Max(0.1f, width * 0.5f); float num2 = Mathf.Cos(angle); float num3 = Mathf.Sin(angle); float num4 = float.MaxValue; float num5 = float.MinValue; float num6 = 0f; float num7 = 0f; int num8 = 0; float[] array = new float[5] { 0f - num, (0f - num) * 0.5f, 0f, num * 0.5f, num }; for (int i = 0; i < array.Length; i++) { float x2 = x + num2 * array[i]; float z2 = z + num3 * array[i]; bool valid; float num9 = SampleSlopeAwareGroundY(x2, z2, distance, biome, out valid); if (!valid) { return false; } num4 = Mathf.Min(num4, num9); num5 = Mathf.Max(num5, num9); float num10 = bottomY - num9; if (num10 > num6) { num6 = num10; } if (0f - num10 > num7) { num7 = 0f - num10; } num8++; } if (isMountainCard) { float num11 = 0f - num3; float num12 = num2; float num13 = Mathf.Min(1.5f, num * 0.4f); float[] array2 = new float[2] { 0f - num13, num13 }; for (int j = 0; j < array2.Length; j++) { float x3 = x + num11 * array2[j]; float z3 = z + num12 * array2[j]; bool valid2; float num14 = SampleSlopeAwareGroundY(x3, z3, distance, biome, out valid2); if (!valid2) { return false; } num4 = Mathf.Min(num4, num14); num5 = Mathf.Max(num5, num14); float num15 = bottomY - num14; if (num15 > num6) { num6 = num15; } if (0f - num15 > num7) { num7 = 0f - num15; } num8++; } } if (num8 == 0) { return false; } maxFloatError = num6; maxBurialError = num7; variation = num5 - num4; return true; } private float BiomeCardHeightMultiplier(Biome biome) { //IL_0000: 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_0042: Unknown result type (might be due to invalid IL or missing references) if (IsSwampBiome(biome) && _enableSwampTreeCards.Value) { return _swampTreeHeightMultiplier.Value; } if (IsMountainBiomeB(biome) && _enableMountainTreeCards.Value) { return _mountainTreeHeightMultiplier.Value; } if (IsPlainsBiomeB(biome) && _enablePlainsSparseTreeCards.Value) { return _plainsTreeHeightMultiplier.Value; } return 1f; } private float BiomeCardWidthMultiplier(Biome biome) { //IL_0000: 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_0042: Unknown result type (might be due to invalid IL or missing references) if (IsSwampBiome(biome) && _enableSwampTreeCards.Value) { return _swampTreeWidthMultiplier.Value; } if (IsMountainBiomeB(biome) && _enableMountainTreeCards.Value) { return _mountainTreeWidthMultiplier.Value; } if (IsPlainsBiomeB(biome) && _enablePlainsSparseTreeCards.Value) { return _plainsTreeWidthMultiplier.Value; } return 1f; } private float ClampGroundCardWidth(float width, Biome biome, ForestPlacementKind kind) { //IL_0024: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) float num = ((kind == ForestPlacementKind.ProxyMass) ? ((_maximumProxyGroundMassWidth != null) ? _maximumProxyGroundMassWidth.Value : 12f) : (IsSwampBiome(biome) ? ((_maximumSwampGroundCardWidth != null) ? _maximumSwampGroundCardWidth.Value : 10f) : (IsPlainsBiomeB(biome) ? ((_maximumPlainsGroundCardWidth != null) ? _maximumPlainsGroundCardWidth.Value : 10f) : ((IsMountainBiomeB(biome) && _enableMountainTreeCards.Value) ? ((_maximumMountainGroundCardWidth != null) ? _maximumMountainGroundCardWidth.Value : 34f) : (((biome & 8) == 0) ? ((_maximumStandardGroundCardWidth != null) ? _maximumStandardGroundCardWidth.Value : 12f) : ((_maximumBlackForestGroundCardWidth != null) ? _maximumBlackForestGroundCardWidth.Value : 46f)))))); return Mathf.Min(Mathf.Max(0.5f, width), Mathf.Max(0.5f, num)); } private void CountBiomeCandidate(Biome biome) { //IL_0000: 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_0030: Unknown result type (might be due to invalid IL or missing references) if (IsSwampBiome(biome)) { _swampCandidates++; } else if (IsMountainBiomeB(biome)) { _mountainCandidates++; } else if (IsPlainsBiomeB(biome)) { _plainsCandidates++; } else { _mixedCandidates++; } } private void CountBiomeAccepted(Biome biome) { //IL_0000: 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_0030: Unknown result type (might be due to invalid IL or missing references) if (IsSwampBiome(biome)) { _swampAccepted++; } else if (IsMountainBiomeB(biome)) { _mountainAccepted++; } else if (IsPlainsBiomeB(biome)) { _plainsAccepted++; } } private string DominantSwampRejectionReason() { if ((Object)(object)_swampBiomeCardMaterial == (Object)null && (Object)(object)_treeCardMaterial == (Object)null) { return "no atlas material at all (both swamp and mixed atlas failed to load)"; } (string, long)[] array = new(string, long)[10] { ("density threshold", _swampRejectedThreshold), ("slope", _swampRejectedSlope), ("water", _swampRejectedWater), ("visible-land ratio", _swampRejectedVisibleLandRatio), ("coastline", _swampRejectedCoastline), ("support/ground-lock", _swampRejectedSupport), ("root anchor (other)", Math.Max(0L, _swampRejectedRootAnchor - _swampRejectedRootDryRatio - _swampRejectedWaterChannel)), ("root dry ratio", _swampRejectedRootDryRatio), ("water channel", _swampRejectedWaterChannel), ("final floating", _swampRejectedFinalFloating) }; string text = "none recorded yet"; long num = 0L; for (int i = 0; i < array.Length; i++) { if (array[i].Item2 > num) { num = array[i].Item2; text = array[i].Item1; } } if (num == 0L) { if (_swampCandidates == 0L) { return "no swamp biome candidates sampled this rebuild (check biome/provider data)"; } if (_swampPassedDensity == 0L) { return "all swamp candidates rejected by density threshold or slope"; } return "no rejections recorded (" + _swampAccepted + " accepted)"; } return text + " (" + num + " rejections)"; } private bool TryGetWaterLevel(out float waterLevel) { if (_waterSurfaceMode.Value == WaterSurfaceMode.Override) { waterLevel = _waterSurfaceHeightOverride.Value; return true; } if ((Object)(object)ZoneSystem.instance != (Object)null) { waterLevel = ZoneSystem.instance.m_waterLevel; return true; } waterLevel = 0f; return _waterSurfaceMode.Value == WaterSurfaceMode.DisableLowlandForest; } private bool IsUnsafeWaterSample(WorldSurfaceSample sample, float waterLevel, Biome cardBiome) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) if ((sample.Biome & 0x100) != 0) { return true; } if (IsAllowedShallowSwampSupport(cardBiome, sample, waterLevel)) { return false; } if (sample.IsWaterOrOcean) { return true; } return sample.GroundY <= waterLevel; } private float MinimumLandAboveWater(Biome biome) { //IL_0000: 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_0017: Unknown result type (might be due to invalid IL or missing references) if (IsSwampBiome(biome)) { return _swampMinimumLandAboveWater.Value; } if ((biome & 0x10) != 0) { return _plainsMinimumLandAboveWater.Value; } return Mathf.Max(_defaultMinimumLandAboveWater.Value, _coastalMinimumLandAboveWater.Value); } private bool HasUnsafeWaterNearFootprint(float x, float z, float radius, float waterLevel, Biome biome, float minimumAboveWater, out GroundRejectReason reason) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) reason = GroundRejectReason.None; float num = radius * 0.70710677f; Vector2[] array = (Vector2[])(object)new Vector2[8] { new Vector2(radius, 0f), new Vector2(0f - radius, 0f), new Vector2(0f, radius), new Vector2(0f, 0f - radius), new Vector2(num, num), new Vector2(num, 0f - num), new Vector2(0f - num, num), new Vector2(0f - num, 0f - num) }; bool flag = IsSwampBiome(biome); for (int i = 0; i < array.Length; i++) { if (!_provider.TrySample(x + array[i].x, z + array[i].y, out var sample) || !sample.Valid) { if (_rejectAnyFootprintSampleUnsupported.Value) { reason = GroundRejectReason.Unsupported; return true; } continue; } if (IsUnsafeWaterSample(sample, waterLevel, biome)) { reason = GroundRejectReason.Water; return true; } if (!flag && sample.GroundY < waterLevel + Mathf.Max(0.05f, minimumAboveWater)) { reason = GroundRejectReason.Water; return true; } } return false; } private static bool IsSwampBiome(Biome biome) { //IL_0000: 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_0004: Invalid comparison between Unknown and I4 return (biome & 2) > 0; } private void RegisterGroundGateReject(ForestPlacementKind kind, GroundRejectReason reason) { if (kind == ForestPlacementKind.ProxyMass) { _groundGateRejectedProxy++; } else { _groundGateRejectedCards++; } switch (reason) { case GroundRejectReason.Water: case GroundRejectReason.BelowWater: case GroundRejectReason.VisibleLandRatio: case GroundRejectReason.CoastlineEdge: _groundGateRejectedWater++; break; case GroundRejectReason.Unsupported: case GroundRejectReason.UncertainSupport: _groundGateRejectedUnsupported++; break; case GroundRejectReason.HeightMismatch: case GroundRejectReason.FinalFloating: _groundGateRejectedHeightMismatch++; break; } } private bool CanRenderCustomGeometry() { if (_provider == null || !_provider.IsReady) { return false; } if (_requireRenderLimits.Value && !_renderLimitsUsable && (!_allowManualEnvelopeWithoutRenderLimits.Value || !(_manualNearWorldExclusionRadius.Value > 0f))) { return false; } return true; } private float ClarityWeatherScale() { if (!_enableHorizonClarity.Value || !_reduceHorizonHaze.Value) { return 1f; } float num = 1f; string weatherClassification = _weatherClassification; string text = ((_weatherName != null) ? _weatherName.ToLowerInvariant() : ""); if (text.Contains("mist") || text.Contains("fog")) { num = _mistWeatherVisibilityBoost.Value; } else if (text.Contains("thunder") || text.Contains("storm")) { num = _stormWeatherVisibilityBoost.Value; } else if (weatherClassification == "clear") { num = _clearWeatherVisibilityBoost.Value; } else if (weatherClassification == "blocked") { num = Mathf.Min(_mistWeatherVisibilityBoost.Value, _stormWeatherVisibilityBoost.Value); } if (_enableRealClearSkies != null && _enableRealClearSkies.Value && _clearSkyTier != ClearSkyWeatherTier.Bad && _clearSkyTier != ClearSkyWeatherTier.SpecialBiome) { num *= _clearSkyAppliedHazeMultiplier; } return Mathf.Lerp(1f, num, Mathf.Clamp01(_weatherFogInfluence.Value)); } private void ApplyClarityColor(Material mat, float alpha) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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) if ((Object)(object)mat == (Object)null) { return; } if (_trueColourDiagnosticTarget != null && _trueColourDiagnosticTarget.Value == TrueColourDiagnosticTarget.NewHorizonsTreeCardMaterials) { Color val = default(Color); ((Color)(ref val))..ctor(0f, 0.9f, 1f, Mathf.Clamp01(alpha)); if (mat.HasProperty("_Color")) { mat.SetColor("_Color", val); } mat.color = val; return; } float num = 1f; if (_enableHorizonClarity.Value && _reduceHorizonHaze.Value) { float num2 = Mathf.Clamp01(_forestDistanceFadeStrength.Value * _horizonHazeStrength.Value * ClarityWeatherScale()); num = Mathf.Lerp(1f, Mathf.Clamp(FarForestDarkness(), 0.4f, 1f), num2); } float num3 = ComputeTreeBrightnessMultiplier(); float num4 = Mathf.Max(num * num3, (_minimumTreeLuminance != null) ? _minimumTreeLuminance.Value : 0.08f); Color val2 = default(Color); ((Color)(ref val2))..ctor(num4, num4, num4, Mathf.Clamp01(alpha)); if (mat.HasProperty("_Color")) { mat.SetColor("_Color", val2); } mat.color = val2; } private void UpdateNaturalTreeLighting() { float num = ComputeRawTreeBrightnessMultiplier(); if (!_treeLightingBlendInitialized) { _smoothedTreeBrightness = num; _treeLightingBlendInitialized = true; } else { float num2 = Mathf.Max(0.5f, (_lightingTransitionSeconds != null) ? _lightingTransitionSeconds.Value : 5f); _smoothedTreeBrightness = Mathf.MoveTowards(_smoothedTreeBrightness, num, Time.unscaledDeltaTime * 2f / num2); } _lastTreeBrightnessForDiagnostics = _smoothedTreeBrightness; bool flag = _trueColourDiagnosticTarget != null && _trueColourDiagnosticTarget.Value == TrueColourDiagnosticTarget.NewHorizonsTreeCardMaterials; float realtimeSinceStartup = Time.realtimeSinceStartup; bool flag2 = _lastClarityWeather != _weatherClassification + "|" + _weatherName; bool flag3 = _lastAppliedTreeBrightness >= 0f && Mathf.Abs(_smoothedTreeBrightness - _lastAppliedTreeBrightness) >= 0.08f; bool flag4 = _forceImmediateTreeMaterialRefresh || flag2 || flag3 || flag; float num3 = ((_minimumTreeMaterialUpdateIntervalSeconds != null) ? Mathf.Max(0.05f, _minimumTreeMaterialUpdateIntervalSeconds.Value) : 0.25f); if (!flag4 && _viewFacingForestOverloadState == ViewFacingForestOverloadState.Soft) { num3 = Mathf.Max(num3, 0.5f); } else if (!flag4 && _viewFacingForestOverloadState == ViewFacingForestOverloadState.Hard) { num3 = Mathf.Max(num3, 0.75f); } if (!flag4 && _lastTreeLightingApplyRealtime >= 0f && realtimeSinceStartup - _lastTreeLightingApplyRealtime < num3) { _treeMaterialUpdatesSkippedByInterval++; return; } float num4 = ((_minimumBrightnessChangeBeforeUpdate != null) ? Mathf.Max(0.001f, _minimumBrightnessChangeBeforeUpdate.Value) : 0.02f); if (_viewFacingForestOverloadState == ViewFacingForestOverloadState.Soft) { num4 = Mathf.Max(num4, 0.04f); } else if (_viewFacingForestOverloadState == ViewFacingForestOverloadState.Hard) { num4 = Mathf.Max(num4, 0.06f); } if (!_treeRendererPropertiesDirty && !flag && !flag2 && _lastAppliedTreeBrightness >= 0f && Mathf.Abs(_smoothedTreeBrightness - _lastAppliedTreeBrightness) < num4) { _treeMaterialUpdatesSkippedByBrightness++; return; } _lastAppliedTreeBrightness = _smoothedTreeBrightness; _lastTreeLightingApplyRealtime = realtimeSinceStartup; ApplyHorizonClarityToCardMaterials(); _forceImmediateTreeMaterialRefresh = false; } private float ComputeTreeBrightnessMultiplier() { if (!_treeLightingBlendInitialized) { _smoothedTreeBrightness = ComputeRawTreeBrightnessMultiplier(); _treeLightingBlendInitialized = true; } return _smoothedTreeBrightness; } private float ComputeRawTreeBrightnessMultiplier() { float num = (_lastAmbientLuminanceForDiagnostics = CurrentAmbientLuminance()); _lastSunElevationForDiagnostics = CurrentSunElevationDegrees(); _lastDaylightFactorForDiagnostics = CurrentDaylightFactor(); if (_naturalDaylightDarkening != null && !_naturalDaylightDarkening.Value) { return 1f; } float num2 = ((_nightTreeBrightness != null) ? _nightTreeBrightness.Value : 0.3f); float num3 = ((_moonlitNightTreeBrightness != null) ? _moonlitNightTreeBrightness.Value : 0.4f); float num4 = Mathf.Lerp(num2, num3, Mathf.InverseLerp(0f, 0.1f, num)); float num5 = ((_twilightTreeBrightness != null) ? _twilightTreeBrightness.Value : 0.55f); float num6 = ((_sunsetTreeBrightness != null) ? _sunsetTreeBrightness.Value : 0.75f); float num7 = ((_lateAfternoonTreeBrightness != null) ? _lateAfternoonTreeBrightness.Value : 1f); float num8 = ((_daylightTreeBrightness != null) ? _daylightTreeBrightness.Value : 1f); float num9 = ((num < 0.25f) ? Mathf.Lerp(num4, num5, Mathf.InverseLerp(0f, 0.25f, num)) : ((num < 0.5f) ? Mathf.Lerp(num5, num6, Mathf.InverseLerp(0.25f, 0.5f, num)) : ((!(num < 0.75f)) ? Mathf.Lerp(num7, num8, Mathf.InverseLerp(0.75f, 1f, num)) : Mathf.Lerp(num6, num7, Mathf.InverseLerp(0.5f, 0.75f, num))))); float num10 = 1f; if (_weatherClassification == "blocked") { num10 = ((_stormTreeBrightness != null) ? _stormTreeBrightness.Value : 0.45f); } else if (_weatherClassification == "light") { num10 = ((_overcastTreeBrightness != null) ? _overcastTreeBrightness.Value : 0.7f); } float num11 = ((_weatherColourInfluence != null) ? Mathf.Clamp01(_weatherColourInfluence.Value) : 0.1f); float num12 = Mathf.Lerp(num9, num9 * num10, num11); float num13 = ((_biomeColourPreservation != null) ? Mathf.Clamp01(_biomeColourPreservation.Value) : 0.9f); return Mathf.Lerp(num12, 1f, num13 * DistanceZonePreservationBlend()); } private float DistanceZonePreservationBlend() { float num = ((_midDistanceOriginalColourStrength != null) ? _midDistanceOriginalColourStrength.Value : 1f); float num2 = ((_farDistanceOriginalColourStrength != null) ? _farDistanceOriginalColourStrength.Value : 0.75f); float num3 = Mathf.Max(1f, ContinuityEnd() - CanopyStart()); float num4 = Mathf.Clamp01((TreeCardEnd() - CanopyStart()) / num3); return Mathf.Lerp(num, num2, num4) * 0.15f; } private void ApplyHorizonClarityToCardMaterials() { _treeMaterialUpdatePasses++; ApplyClarityColor(_treeCardMaterial, FarTreeAlpha()); ApplyClarityColor(_canopyCardMaterial, FarCanopyAlpha()); ApplyClarityColor(_mountainBiomeCardMaterial, FarTreeAlpha()); ApplyClarityColor(_swampBiomeCardMaterial, FarTreeAlpha()); ApplyNearHandoffColourToBoundaryChunks(); ApplyRingAlphaFloorToNonBoundaryChunks(); _lastClarityWeather = _weatherClassification + "|" + _weatherName; _treeRendererPropertiesDirty = false; } private float RingMinimumAlpha(ForestRing ring) { switch (ring) { case ForestRing.Handoff: if (_nearHandoffMinimumAlpha == null) { return 0.95f; } return _nearHandoffMinimumAlpha.Value; case ForestRing.Near: case ForestRing.Mid: if (_midDistanceMinimumAlpha == null) { return 0.85f; } return _midDistanceMinimumAlpha.Value; case ForestRing.Far: if (_farDistanceMinimumAlpha == null) { return 0.65f; } return _farDistanceMinimumAlpha.Value; default: if (_horizonMinimumAlpha == null) { return 0.45f; } return _horizonMinimumAlpha.Value; } } private void ApplyRingAlphaFloorToNonBoundaryChunks() { if (_trueColourDiagnosticTarget != null && _trueColourDiagnosticTarget.Value == TrueColourDiagnosticTarget.NewHorizonsTreeCardMaterials) { return; } float num = ComputeTreeBrightnessMultiplier(); float num2 = 1f; if (_enableHorizonClarity.Value && _reduceHorizonHaze.Value) { float num3 = Mathf.Clamp01(_forestDistanceFadeStrength.Value * _horizonHazeStrength.Value * ClarityWeatherScale()); num2 = Mathf.Lerp(1f, Mathf.Clamp(FarForestDarkness(), 0.4f, 1f), num3); } float brightness = Mathf.Max(num2 * num, (_minimumTreeLuminance != null) ? _minimumTreeLuminance.Value : 0.12f); float num4 = FarTreeAlpha(); float num5 = FarCanopyAlpha(); foreach (ForestTile value in _forestTiles.Values) { for (int i = 0; i < value.Chunks.Count; i++) { ForestChunk forestChunk = value.Chunks[i]; float num6 = FlatDistance(_buildAnchor.x, _buildAnchor.z, forestChunk.Center.x, forestChunk.Center.z); float num7 = forestChunk.Size * 0.707107f; float num8 = NativeTreelineHandoff(); float num9 = ((_nearHandoffColourBandWidth != null) ? Mathf.Max(0f, _nearHandoffColourBandWidth.Value) : 800f); float num10 = Mathf.Max(0f, num6 - num7); if ((_preserveOriginalColourNearHandoff != null && !_preserveOriginalColourNearHandoff.Value) || !(num6 + num7 >= num8) || !(num10 <= num8 + num9)) { float num11 = RingMinimumAlpha(RingForDistance(num6)); float alpha = Mathf.Max(num4, num11); float alpha2 = Mathf.Max(num5, num11); SetRingAlphaPropertyBlock((Renderer)(object)forestChunk.TreeRenderer, brightness, alpha); SetRingAlphaPropertyBlock((Renderer)(object)forestChunk.CanopyRenderer, brightness, alpha2); SetRingAlphaPropertyBlock((Renderer)(object)forestChunk.MountainBiomeRenderer, brightness, alpha); SetRingAlphaPropertyBlock((Renderer)(object)forestChunk.SwampBiomeRenderer, brightness, alpha); } } } } private void SetRingAlphaPropertyBlock(Renderer renderer, float brightness, float alpha) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)renderer == (Object)null)) { Color colour = default(Color); ((Color)(ref colour))..ctor(brightness, brightness, brightness, Mathf.Clamp01(alpha)); ApplyTreeRendererColourBlock(renderer, colour); } } private void ApplyNearHandoffColourToBoundaryChunks() { //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) bool flag = _preserveOriginalColourNearHandoff == null || _preserveOriginalColourNearHandoff.Value; int num = 0; float num2 = ComputeTreeBrightnessMultiplier(); float num3 = Mathf.Clamp01((_nearHandoffDaylightOriginalColourStrength != null) ? _nearHandoffDaylightOriginalColourStrength.Value : 1f); float num4 = Mathf.Clamp01((_nearHandoffWeatherColourInfluence != null) ? _nearHandoffWeatherColourInfluence.Value : 0.05f); float num5 = Mathf.Clamp01((_nearHandoffFogColourInfluence != null) ? _nearHandoffFogColourInfluence.Value : 0f); float num6 = ((_nearHandoffMinimumDaylightBrightness != null) ? _nearHandoffMinimumDaylightBrightness.Value : 0.95f); float num7 = ((_nearHandoffMaximumDaylightBrightness != null) ? _nearHandoffMaximumDaylightBrightness.Value : 1.05f); float num8 = Mathf.Clamp01(_lastDaylightFactorForDiagnostics); float num9 = 1f; if (_weatherClassification == "blocked") { num9 = ((_stormTreeBrightness != null) ? _stormTreeBrightness.Value : 0.45f); } else if (_weatherClassification == "light") { num9 = ((_overcastTreeBrightness != null) ? _overcastTreeBrightness.Value : 0.7f); } float num10 = Mathf.Lerp(num2, num2 * num9, num4); Color val = (_fogColourDiagnosticApplied ? _savedFogColour : RenderSettings.fogColor); float num11 = Mathf.Clamp01(0.2126f * val.r + 0.7152f * val.g + 0.0722f * val.b); float num12 = Mathf.Lerp(num10, num11, num5); float num13 = Mathf.Lerp(num12, 1f, num3 * num8); float num14 = ((_minimumTreeLuminance != null) ? _minimumTreeLuminance.Value : 0.12f); float num15 = Mathf.Lerp(num14, num6, num8); float brightness = (_lastNearHandoffBrightnessForDiagnostics = Mathf.Clamp(num13, num15, num7)); float num16 = NativeTreelineHandoff(); float num17 = ((_nearHandoffColourBandWidth != null) ? Mathf.Max(0f, _nearHandoffColourBandWidth.Value) : 800f); foreach (ForestTile value in _forestTiles.Values) { for (int i = 0; i < value.Chunks.Count; i++) { ForestChunk forestChunk = value.Chunks[i]; float num18 = FlatDistance(_buildAnchor.x, _buildAnchor.z, forestChunk.Center.x, forestChunk.Center.z); float num19 = forestChunk.Size * 0.707107f; float num20 = Mathf.Max(0f, num18 - num19); float num21 = num18 + num19; bool flag2 = num21 >= num16 && num20 <= num16 + num17; if (!flag || !flag2) { ClearNearHandoffPropertyBlock((Renderer)(object)forestChunk.TreeRenderer); ClearNearHandoffPropertyBlock((Renderer)(object)forestChunk.CanopyRenderer); ClearNearHandoffPropertyBlock((Renderer)(object)forestChunk.MountainBiomeRenderer); ClearNearHandoffPropertyBlock((Renderer)(object)forestChunk.SwampBiomeRenderer); } else { SetNearHandoffPropertyBlock((Renderer)(object)forestChunk.TreeRenderer, brightness, FarTreeAlpha()); SetNearHandoffPropertyBlock((Renderer)(object)forestChunk.CanopyRenderer, brightness, FarCanopyAlpha()); SetNearHandoffPropertyBlock((Renderer)(object)forestChunk.MountainBiomeRenderer, brightness, FarTreeAlpha()); SetNearHandoffPropertyBlock((Renderer)(object)forestChunk.SwampBiomeRenderer, brightness, FarTreeAlpha()); num++; } } } _nearHandoffChunksTinted = num; } private void SetNearHandoffPropertyBlock(Renderer renderer, float brightness, float alpha) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)renderer == (Object)null)) { if (_trueColourDiagnosticTarget != null && _trueColourDiagnosticTarget.Value == TrueColourDiagnosticTarget.NewHorizonsTreeCardMaterials) { ClearNearHandoffPropertyBlock(renderer); return; } Color colour = default(Color); ((Color)(ref colour))..ctor(brightness, brightness, brightness, Mathf.Clamp01(alpha)); ApplyTreeRendererColourBlock(renderer, colour); } } private void ApplyTreeRendererColourBlock(Renderer renderer, Color colour) { //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0078: 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_00a0: 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_012b: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)renderer == (Object)null) { return; } int instanceID = ((Object)renderer).GetInstanceID(); if (_treeRendererPropertyStates.TryGetValue(instanceID, out var value)) { float num = ((_minimumBrightnessChangeBeforeUpdate != null) ? Mathf.Max(0.001f, _minimumBrightnessChangeBeforeUpdate.Value) : 0.02f); float num2 = Mathf.Max(Mathf.Abs(value.Colour.r - colour.r), Mathf.Max(Mathf.Abs(value.Colour.g - colour.g), Mathf.Abs(value.Colour.b - colour.b))); if (num2 < num && Mathf.Abs(value.Colour.a - colour.a) < 0.001f) { return; } } if (_treeRendererPropertyBlock == null) { _treeRendererPropertyBlock = new MaterialPropertyBlock(); } _treeRendererPropertyBlock.Clear(); Material sharedMaterial = renderer.sharedMaterial; if ((Object)(object)sharedMaterial == (Object)null || sharedMaterial.HasProperty("_Color")) { _treeRendererPropertyBlock.SetColor("_Color", colour); } if ((Object)(object)sharedMaterial != (Object)null && sharedMaterial.HasProperty("_Color2")) { _treeRendererPropertyBlock.SetColor("_Color2", colour); } if ((Object)(object)sharedMaterial != (Object)null && sharedMaterial.HasProperty("_TintColor")) { _treeRendererPropertyBlock.SetColor("_TintColor", colour); } if ((Object)(object)sharedMaterial != (Object)null && sharedMaterial.HasProperty("_BaseColor")) { _treeRendererPropertyBlock.SetColor("_BaseColor", colour); } renderer.SetPropertyBlock(_treeRendererPropertyBlock); _treeRendererPropertyStates[instanceID] = new TreeRendererPropertyState { Colour = colour }; _treePropertyBlockWrites++; } private void ClearNearHandoffPropertyBlock(Renderer renderer) { if (!((Object)(object)renderer == (Object)null)) { int instanceID = ((Object)renderer).GetInstanceID(); if (_treeRendererPropertyStates.Remove(instanceID)) { renderer.SetPropertyBlock((MaterialPropertyBlock)null); _treePropertyBlockWrites++; } } } private bool UsesFullResolutionProviderTerrainColour() { if (_enableTrueColourDistantLand != null && _enableTrueColourDistantLand.Value && _useFullResolutionProviderTerrainColour != null && _useFullResolutionProviderTerrainColour.Value && _provider != null && _provider.UsesSharedTerrainTexture && (Object)(object)_provider.SharedTerrainTexture != (Object)null) { return (Object)(object)_sharedTerrainMaterial != (Object)null; } return false; } private void UpdateSharedTerrainMaterialLighting() { //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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0142: 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_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_sharedTerrainMaterial == (Object)null || !UsesFullResolutionProviderTerrainColour()) { return; } if (_trueColourDiagnosticTarget != null && _trueColourDiagnosticTarget.Value == TrueColourDiagnosticTarget.NewHorizonsFarTerrain) { Color val = default(Color); ((Color)(ref val))..ctor(1f, 0f, 0.9f, 1f); _sharedTerrainMaterial.color = val; if (_sharedTerrainMaterial.HasProperty("_Color")) { _sharedTerrainMaterial.SetColor("_Color", val); } _lastSharedTerrainMaterialColour = val; return; } if (HasExactClearDayProviderContract()) { Color white = Color.white; _sharedTerrainMaterial.color = white; if (_sharedTerrainMaterial.HasProperty("_Color")) { _sharedTerrainMaterial.SetColor("_Color", white); } _lastSharedTerrainMaterialColour = white; _terrainColourRadialMultiplierActive = false; return; } float num = CurrentDaylightFactor(); float num2 = ((_preserveNightTerrainDarkness == null || _preserveNightTerrainDarkness.Value) ? Mathf.Lerp(0.35f, 1f, num) : 1f); if (_weatherClassification == "blocked") { num2 *= 0.72f; } else if (_weatherClassification == "light") { num2 *= 0.88f; } float num3 = ComputeTrueColourAmount(); Color fogColor = RenderSettings.fogColor; float num4 = Mathf.Clamp(0.2126f * fogColor.r + 0.7152f * fogColor.g + 0.0722f * fogColor.b, 0.35f, 1f); Color val2 = default(Color); ((Color)(ref val2))..ctor(Mathf.Lerp(fogColor.r, num4, 0.35f), Mathf.Lerp(fogColor.g, num4, 0.35f), Mathf.Lerp(fogColor.b, num4, 0.35f), 1f); Color val3 = Color.Lerp(val2, Color.white, num3); val3.r = Mathf.Clamp01(val3.r * num2); val3.g = Mathf.Clamp01(val3.g * num2); val3.b = Mathf.Clamp01(val3.b * num2); val3.a = 1f; _sharedTerrainMaterial.color = val3; if (_sharedTerrainMaterial.HasProperty("_Color")) { _sharedTerrainMaterial.SetColor("_Color", val3); } _lastSharedTerrainMaterialColour = val3; } private Color32 ComputeTerrainDisplayColor(float worldX, float worldZ, float distance) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_010f: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) WorldSurfaceSample sample = default(WorldSurfaceSample); bool flag = _provider != null && _provider.TrySample(worldX, worldZ, out sample) && sample.Valid; Color val = ((_provider != null) ? _provider.GetTerrainColor(worldX, worldZ, distance) : Color.gray); if (!flag) { return Color32.op_Implicit(val); } Color val2 = ParseColor(_forestTerrainTintColour.Value, new Color(0.14f, 0.23f, 0.17f, 1f)); float forestMask; float distanceMask; float tintStrength; float num = CalculateTerrainTintAmount(sample, distance, out forestMask, out distanceMask, out tintStrength); Color val3 = Color.Lerp(val, val2, num); if (_trueColourDiagnosticTarget != null && _trueColourDiagnosticTarget.Value == TrueColourDiagnosticTarget.NewHorizonsTerrainTint) { return Color32.op_Implicit((Color)((num > 0.001f) ? new Color(1f, 0.85f, 0f, 1f) : val)); } if (_trueColourDiagnosticTarget != null && _trueColourDiagnosticTarget.Value == TrueColourDiagnosticTarget.ForestTerrainTint) { return Color32.op_Implicit((Color)((forestMask > 0.001f) ? new Color(1f, 0.35f, 0f, 1f) : val)); } float num2 = Smooth01(Mathf.InverseLerp(7f, 42f, sample.SlopeDegrees)); float num3 = Smooth01(Mathf.InverseLerp(VisualExclusionRadius(), Mathf.Max(VisualExclusionRadius() + 1f, FarTerrainViewDistance()), distance)); float num4 = 1f - num2 * num3 * _terrainSlopeShadingStrength.Value; float num5 = Mathf.Clamp01(Mathf.InverseLerp(20f, 145f, sample.GroundY)) * 0.08f * num3; Color val4 = val3 * Mathf.Clamp(num4 + num5, 0.45f, 1.12f); val4.a = 1f; if (_enableHorizonClarity.Value && _reduceHorizonHaze.Value) { float num6 = Smooth01(Mathf.InverseLerp(VisualExclusionRadius(), Mathf.Max(VisualExclusionRadius() + 1f, FarTerrainViewDistance()), distance)); float num7 = Mathf.Clamp01(num6 * _terrainDistanceFadeStrength.Value * _horizonHazeStrength.Value * ClarityWeatherScale()); float num8 = Mathf.Lerp(1f, Mathf.Clamp(Mathf.Max(FarTerrainContrast(), FarForestContrast() * forestMask), 0.5f, 2.5f), num7); val4.r = Mathf.Clamp01((val4.r - 0.5f) * num8 + 0.5f); val4.g = Mathf.Clamp01((val4.g - 0.5f) * num8 + 0.5f); val4.b = Mathf.Clamp01((val4.b - 0.5f) * num8 + 0.5f); float num9 = Mathf.Lerp(1f, Mathf.Clamp(FarTerrainDarkness(), 0.4f, 1.2f), num7); val4.r = Mathf.Clamp01(val4.r * num9); val4.g = Mathf.Clamp01(val4.g * num9); val4.b = Mathf.Clamp01(val4.b * num9); val4.a = 1f; } if (_trueColourDiagnosticTarget != null && _trueColourDiagnosticTarget.Value == TrueColourDiagnosticTarget.NewHorizonsHaze) { return Color32.op_Implicit((Color)((_enableHorizonClarity.Value && _reduceHorizonHaze.Value) ? new Color(0.55f, 0f, 1f, 1f) : val4)); } val4 = ApplyTrueColourDistantLand(val4, val, distance); return Color32.op_Implicit(val4); } private Color ApplyTrueColourDistantLand(Color shaded, Color baseColor, float distance) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_0075: 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_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) if (_trueColourDiagnosticTarget != null && _trueColourDiagnosticTarget.Value == TrueColourDiagnosticTarget.NewHorizonsFarTerrain) { return new Color(1f, 0f, 0.9f, shaded.a); } if (_enableTrueColourDistantLand == null || !_enableTrueColourDistantLand.Value) { return shaded; } if (HasExactClearDayProviderContract()) { _terrainColourRadialMultiplierActive = false; baseColor.a = shaded.a; return baseColor; } float num = ComputeTrueColourAmount(); if (num <= 0.0001f) { return shaded; } float num2 = Mathf.Clamp01((_clearWeatherOriginalTerrainColourStrength != null) ? _clearWeatherOriginalTerrainColourStrength.Value : 1f); float num3 = Mathf.Clamp01((_clearWeatherAtmosphericColourStrength != null) ? _clearWeatherAtmosphericColourStrength.Value : 0f); float num4 = Mathf.Max(0.0001f, num2 + num3); float num5 = Mathf.Clamp01(num2 / num4 * num); if (IsEligibleClearDayTerrainColour() && !HasExactClearDayProviderContract()) { float num6 = Mathf.Max(0f, (_radialTerrainColourTransitionWidth != null) ? _radialTerrainColourTransitionWidth.Value : 500f); if (num6 > 0.01f) { float num7 = Smooth01(Mathf.InverseLerp(VisualExclusionRadius(), VisualExclusionRadius() + num6, distance)); num5 = Mathf.Lerp(num2, num5, num7); _terrainColourRadialMultiplierActive = num7 < 0.999f; } } Color val = Color.Lerp(shaded, baseColor, num5); float num8 = Mathf.Clamp01((_clearWeatherDistantSaturationStrength != null) ? _clearWeatherDistantSaturationStrength.Value : 0f); if (num8 > 0.001f) { float num9 = default(float); float num11 = default(float); float num10 = default(float); Color.RGBToHSV(val, ref num9, ref num10, ref num11); num10 = Mathf.Clamp01(Mathf.Lerp(num10, num10 * (1f - num8), num)); val = Color.HSVToRGB(num9, num10, num11); } float num12 = Mathf.Clamp01((_clearWeatherMaximumTerrainDarkening != null) ? _clearWeatherMaximumTerrainDarkening.Value : 0f); float num13 = 0.2126f * baseColor.r + 0.7152f * baseColor.g + 0.0722f * baseColor.b; float num14 = 0.2126f * val.r + 0.7152f * val.g + 0.0722f * val.b; if (num13 > 0.0001f && num14 < num13 * (1f - num12)) { float num15 = num13 * (1f - num12); float num16 = ((num14 > 0.0001f) ? (num15 / num14) : 1f); val.r = Mathf.Clamp01(val.r * num16); val.g = Mathf.Clamp01(val.g * num16); val.b = Mathf.Clamp01(val.b * num16); } val.a = shaded.a; return val; } private bool IsEligibleClearDayTerrainColour() { if (_enableTrueColourDistantLand != null && _enableTrueColourDistantLand.Value) { return ComputeTrueColourTargetAmount() >= 0.999f; } return false; } private bool HasExactClearDayProviderContract() { if (!IsEligibleClearDayTerrainColour()) { return false; } float num = ((_clearWeatherOriginalTerrainColourStrength != null) ? _clearWeatherOriginalTerrainColourStrength.Value : 1f); float num2 = ((_clearWeatherAtmosphericColourStrength != null) ? _clearWeatherAtmosphericColourStrength.Value : 0f); float num3 = ((_clearWeatherMaximumTerrainDarkening != null) ? _clearWeatherMaximumTerrainDarkening.Value : 0f); float num4 = ((_clearWeatherDistantSaturationStrength != null) ? _clearWeatherDistantSaturationStrength.Value : 0f); if (num >= 0.999f && num2 <= 0.001f && num3 <= 0.001f) { return num4 <= 0.001f; } return false; } private void UpdateTerrainColourRingDiagnostics() { //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_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_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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) if (_provider != null && _provider.IsReady && !(Time.unscaledTime < _nextTerrainColourDiagnosticUpdate)) { _nextTerrainColourDiagnosticUpdate = Time.unscaledTime + 1f; float num = VisualExclusionRadius(); float num2 = Mathf.Max(num + 2f, FarTerrainViewDistance() - 2f); float distance = Mathf.Lerp(num, num2, 0.65f); _terrainColourDiagnosticNear = EvaluateTerrainColourForDiagnostics(num + 1f, out var providerColour); _terrainColourDiagnosticFar = EvaluateTerrainColourForDiagnostics(distance, out var providerColour2); _terrainColourDiagnosticHorizon = EvaluateTerrainColourForDiagnostics(num2, out var providerColour3); _terrainColourDiagnosticProvider = providerColour; _terrainColourDiagnosticNearRatio = LuminanceRatio(_terrainColourDiagnosticNear, providerColour); _terrainColourDiagnosticFarRatio = LuminanceRatio(_terrainColourDiagnosticFar, providerColour2); _terrainColourDiagnosticHorizonRatio = LuminanceRatio(_terrainColourDiagnosticHorizon, providerColour3); _terrainColourPostCorrectionDarkening = IsEligibleClearDayTerrainColour() && (_terrainColourDiagnosticNearRatio < 0.98f || _terrainColourDiagnosticFarRatio < 0.98f || _terrainColourDiagnosticHorizonRatio < 0.98f); _terrainColourProviderSpace = (_provider.UsesSharedTerrainTexture ? "Unity sRGB terrain texture; no manual conversion" : "Unity Color procedural provider; no colour-space conversion"); if (!_terrainColourRingSourceLogged) { _terrainColourRingSourceLogged = true; string text = FindNativeTerrainMaterialName(); string text2 = ((UsesFullResolutionProviderTerrainColour() && (Object)(object)_sharedTerrainMaterial != (Object)null) ? ((Object)_sharedTerrainMaterial).name : "Donegal Horizon per-tile terrain material"); float num3 = 1f; float num4 = (UsesFullResolutionProviderTerrainColour() ? TerrainColourLuminance(_lastSharedTerrainMaterialColour) : _terrainColourDiagnosticFarRatio); ((BaseUnityPlugin)this).Logger.LogInfo((object)("TERRAIN COLOUR RING SOURCE IDENTIFIED | source=native/New Horizons material handoff at the effective exclusion radius plus legacy procedural provider distance darkening beginning at 1200m | transition distance=" + num.ToString("F0", CultureInfo.InvariantCulture) + "m | near material=" + text + " | far material=" + text2 + " | near colour multiplier=" + num3.ToString("F3", CultureInfo.InvariantCulture) + " | far colour multiplier=" + num4.ToString("F3", CultureInfo.InvariantCulture) + " | near luminance=" + TerrainColourLuminance(_terrainColourDiagnosticNear).ToString("F3", CultureInfo.InvariantCulture) + " | far luminance=" + TerrainColourLuminance(_terrainColourDiagnosticFar).ToString("F3", CultureInfo.InvariantCulture) + ".")); } } } private Color EvaluateTerrainColourForDiagnostics(float distance, out Color providerColour) { //IL_0033: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_0051: Unknown result type (might be due to invalid IL or missing references) float worldX = _buildAnchor.x + distance; float z = _buildAnchor.z; providerColour = ((_provider != null) ? _provider.GetTerrainColor(worldX, z, distance) : Color.gray); if (UsesFullResolutionProviderTerrainColour()) { return MultiplyTerrainColours(providerColour, _lastSharedTerrainMaterialColour); } return Color32.op_Implicit(ComputeTerrainDisplayColor(worldX, z, distance)); } private static Color MultiplyTerrainColours(Color a, Color b) { //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_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_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_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_0048: Unknown result type (might be due to invalid IL or missing references) return new Color(Mathf.Clamp01(a.r * b.r), Mathf.Clamp01(a.g * b.g), Mathf.Clamp01(a.b * b.b), Mathf.Clamp01(a.a * b.a)); } private static float TerrainColourLuminance(Color colour) { //IL_000a: 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_0023: Unknown result type (might be due to invalid IL or missing references) return Mathf.Max(0f, 0.2126f * colour.r + 0.7152f * colour.g + 0.0722f * colour.b); } private static string FormatTerrainColour(Color colour) { return colour.r.ToString("F3", CultureInfo.InvariantCulture) + "," + colour.g.ToString("F3", CultureInfo.InvariantCulture) + "," + colour.b.ToString("F3", CultureInfo.InvariantCulture); } private static float LuminanceRatio(Color finalColour, Color providerColour) { //IL_0000: 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) float num = TerrainColourLuminance(providerColour); if (!(num > 0.0001f)) { return 1f; } return TerrainColourLuminance(finalColour) / num; } private static string FindNativeTerrainMaterialName() { try { Heightmap[] array = Object.FindObjectsByType((FindObjectsSortMode)0); FieldInfo field = typeof(Heightmap).GetField("m_material", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < array.Length; i++) { Material val = (Material)((field != null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val != (Object)null) { return ((Object)val).name; } Renderer val2 = (((Object)(object)array[i] != (Object)null) ? ((Component)array[i]).GetComponent() : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMaterial != (Object)null) { return ((Object)val2.sharedMaterial).name; } } } catch { } return "Valheim Heightmap native terrain material"; } private void UpdateTrueColourBlend() { _trueColourTargetBlend = ComputeTrueColourTargetAmount(); if (!_trueColourBlendInitialized) { _trueColourCurrentBlend = 0f; _trueColourBlendInitialized = true; } float num = Mathf.Max(0.5f, (_trueColourBlendSeconds != null) ? _trueColourBlendSeconds.Value : 6f); _trueColourCurrentBlend = Mathf.MoveTowards(_trueColourCurrentBlend, _trueColourTargetBlend, Time.unscaledDeltaTime / num); } private float ComputeTrueColourAmount() { if (_enableTrueColourDistantLand == null || !_enableTrueColourDistantLand.Value) { return 0f; } return Mathf.Clamp01(_trueColourBlendInitialized ? _trueColourCurrentBlend : ComputeTrueColourTargetAmount()); } private float ComputeTrueColourTargetAmount() { if (_enableTrueColourDistantLand == null || !_enableTrueColourDistantLand.Value) { return 0f; } if (_preserveSpecialBiomeAtmosphereTerrain == null || _preserveSpecialBiomeAtmosphereTerrain.Value) { string text = TryGetPlayerBiomeName(); if (!string.IsNullOrEmpty(text)) { string text2 = text.ToLowerInvariant(); if (text2.Contains("mistlands") || text2.Contains("ashlands") || text2.Contains("deepnorth")) { return 0f; } } } float num = ((_weatherClassification == "clear") ? 1f : ((_weatherClassification == "light") ? 0.5f : ((!(_weatherClassification == "blocked")) ? 0f : ((_preserveStormTerrainAtmosphere == null || _preserveStormTerrainAtmosphere.Value) ? 0f : 1f)))); float num2 = CurrentDaylightFactor(); if ((_preserveNightTerrainDarkness == null || _preserveNightTerrainDarkness.Value) && num2 < 0.45f) { num *= Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.1f, 0.45f, num2)); } if (_preserveSunriseAndSunsetColourTrueColour == null || _preserveSunriseAndSunsetColourTrueColour.Value) { float num3 = CurrentSunElevationDegrees(); if ((Object)(object)RenderSettings.sun != (Object)null && num3 > -8f && num3 < 12f) { num *= Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(4f, 12f, num3)); } } return Mathf.Clamp01(num); } private static float CurrentSunElevationDegrees() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)RenderSettings.sun == (Object)null) { return -90f; } return Mathf.Asin(Mathf.Clamp(0f - ((Component)RenderSettings.sun).transform.forward.y, -1f, 1f)) * 57.29578f; } private static float CurrentAmbientLuminance() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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) Color ambientLight = RenderSettings.ambientLight; return Mathf.Clamp01(0.2126f * ambientLight.r + 0.7152f * ambientLight.g + 0.0722f * ambientLight.b); } private static float CurrentDaylightFactor() { float num = Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.08f, 0.8f, CurrentAmbientLuminance())); if ((Object)(object)RenderSettings.sun == (Object)null) { return num; } float num2 = Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(-6f, 35f, CurrentSunElevationDegrees())); return Mathf.Clamp01(Mathf.Max(num2, num * 0.75f)); } private string BuildTerrainTintDiagnostic(Vector3 worldPosition, float distance) { //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) WorldSurfaceSample sample = default(WorldSurfaceSample); if (_provider == null || !_provider.TrySample(worldPosition.x, worldPosition.z, out sample) || !sample.Valid) { return "sample unavailable"; } float forestMask; float distanceMask; float tintStrength; float num = CalculateTerrainTintAmount(sample, distance, out forestMask, out distanceMask, out tintStrength); float num2 = Smooth01(Mathf.InverseLerp(7f, 42f, sample.SlopeDegrees)); float num3 = Smooth01(Mathf.InverseLerp(VisualExclusionRadius(), Mathf.Max(VisualExclusionRadius() + 1f, FarTerrainViewDistance()), distance)); float num4 = num2 * num3 * _terrainSlopeShadingStrength.Value; return "distance " + Mathf.RoundToInt(distance) + "m, forestMask " + forestMask.ToString("F2", CultureInfo.InvariantCulture) + ", distanceMask " + distanceMask.ToString("F2", CultureInfo.InvariantCulture) + ", tintStrength " + tintStrength.ToString("F2", CultureInfo.InvariantCulture) + ", tint " + num.ToString("F2", CultureInfo.InvariantCulture) + ", slopeShade " + num4.ToString("F2", CultureInfo.InvariantCulture); } private float CalculateTerrainTintAmount(WorldSurfaceSample sample, float distance, out float forestMask, out float distanceMask, out float tintStrength) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(sample.ForestDensity * ForestDensityMultiplier()); forestMask = Mathf.Clamp01((num - ForestDensityThreshold()) / Mathf.Max(0.01f, 1f - ForestDensityThreshold())); forestMask *= Mathf.Clamp01(BiomeForestMultiplier(sample.Biome)); distanceMask = Smooth01(Mathf.InverseLerp(FarForestStartDistance(), FarForestEndDistance(), distance)); tintStrength = Mathf.Clamp01(Mathf.Max(ForestTerrainTintStrength(), DistanceTintStrength())); return Mathf.Clamp01(forestMask * distanceMask * tintStrength); } private static float Smooth01(float value) { value = Mathf.Clamp01(value); return value * value * (3f - 2f * value); } private static float FlatDistance(Vector3 a, Vector3 b) { //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) return FlatDistance(a.x, a.z, b.x, b.z); } private static float FlatDistance(float ax, float az, float bx, float bz) { float num = ax - bx; float num2 = az - bz; return Mathf.Sqrt(num * num + num2 * num2); } private static float DistanceToTile(float worldX, float worldZ, int tileX, int tileZ, float tileSize) { float num = (float)tileX * tileSize; float num2 = num + tileSize; float num3 = (float)tileZ * tileSize; float num4 = num3 + tileSize; float num5 = ((worldX < num) ? (num - worldX) : ((worldX > num2) ? (worldX - num2) : 0f)); float num6 = ((worldZ < num3) ? (num3 - worldZ) : ((worldZ > num4) ? (worldZ - num4) : 0f)); return Mathf.Sqrt(num5 * num5 + num6 * num6); } private static Material CreateTextureMaterial(Texture2D texture, string name) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) Shader val = FindShader("Unlit/Texture", "Legacy Shaders/Diffuse"); if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("No usable opaque terrain shader was found."); } Material val2 = new Material(val); ((Object)val2).name = name; val2.mainTexture = (Texture)(object)texture; val2.color = Color.white; val2.renderQueue = 2000; if (val2.HasProperty("_Cull")) { val2.SetInt("_Cull", 0); } if (val2.HasProperty("_ZWrite")) { val2.SetInt("_ZWrite", 1); } return val2; } private static Material CreateColorMaterial(Color color, string name) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_003f: 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) Shader val = FindShader("Unlit/Color", "Legacy Shaders/Diffuse"); if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("No usable opaque colour shader was found."); } Material val2 = new Material(val); ((Object)val2).name = name; val2.color = color; if (val2.HasProperty("_Color")) { val2.SetColor("_Color", color); } val2.renderQueue = 2000; if (val2.HasProperty("_Cull")) { val2.SetInt("_Cull", 0); } if (val2.HasProperty("_ZWrite")) { val2.SetInt("_ZWrite", 1); } return val2; } private Material TryCreateCutoutTextureMaterial(Texture2D texture, string name, string layerName, out string shaderName) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown shaderName = "none"; Shader val = FindShader("Unlit/Transparent Cutout", "Legacy Shaders/Transparent/Cutout/Diffuse", "Standard"); if ((Object)(object)val != (Object)null) { Material val2 = new Material(val); ((Object)val2).name = name; ApplyAtlasMaterialProperties(val2, texture, forceCutoutDefaults: true); shaderName = ((Object)val).name; ((BaseUnityPlugin)this).Logger.LogInfo((object)(layerName + " atlas material created using explicit cutout shader. Shader: " + shaderName + ".")); return val2; } _lastAtlasMaterialError = layerName + ": explicit cutout shaders unavailable"; _nextAtlasMaterialRetry = Time.unscaledTime + 5f; ((BaseUnityPlugin)this).Logger.LogInfo((object)(layerName + " atlas texture is loaded; waiting for a compatible live Valheim vegetation material. The atlas barrier remains active and retry is bounded to one attempt every five seconds.")); shaderName = "none"; return null; } private void ApplySwampDiagnosticColourIfNeeded() { //IL_008e: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) bool flag = _debugSwampCardTypeColours != null && _debugSwampCardTypeColours.Value; if (flag == _swampDiagnosticColourApplied) { return; } _swampDiagnosticColourApplied = flag; if ((Object)(object)_swampBiomeCardMaterial == (Object)null) { return; } if (flag) { if (!_swampDiagnosticOriginalColourCaptured) { _swampDiagnosticOriginalColour = _swampBiomeCardMaterial.color; _swampDiagnosticOriginalColourCaptured = true; } _swampBiomeCardMaterial.color = new Color(1f, 0f, 0.85f, 1f); } else if (_swampDiagnosticOriginalColourCaptured) { _swampBiomeCardMaterial.color = _swampDiagnosticOriginalColour; } } private void RetryAtlasMaterialsIfNeeded() { bool flag = (Object)(object)_treeAtlasTexture != (Object)null && ((Object)(object)_treeCardMaterial == (Object)null || !_treeCardCutoutMaterialValid); bool flag2 = (Object)(object)_canopyAtlasTexture != (Object)null && (Object)(object)_canopyCardMaterial == (Object)null; bool flag3 = (Object)(object)_mountainBiomeAtlasTexture != (Object)null && (Object)(object)_mountainBiomeCardMaterial == (Object)null; bool flag4 = (Object)(object)_swampBiomeAtlasTexture != (Object)null && (Object)(object)_swampBiomeCardMaterial == (Object)null; if ((!flag && !flag2 && !flag3 && !flag4) || Time.unscaledTime < _nextAtlasMaterialRetry) { return; } _nextAtlasMaterialRetry = Time.unscaledTime + 5f; if (!TryFindAtlasFallbackCandidate(out var best, out var failure)) { if (flag) { _treeAtlasStatus = "waiting for compatible shader"; _treeAtlasShader = "none"; } if (flag2) { _canopyAtlasStatus = "waiting for compatible shader"; _canopyAtlasShader = "none"; } if (flag3) { _mountainBiomeAtlasStatus = "waiting for compatible shader"; _mountainBiomeAtlasShader = "none"; } if (flag4) { _swampBiomeAtlasStatus = "waiting for compatible shader"; _swampBiomeAtlasShader = "none"; } _lastAtlasMaterialError = failure; return; } bool flag5 = false; if (flag) { if ((Object)(object)_treeCardMaterial != (Object)null) { Object.Destroy((Object)(object)_treeCardMaterial); } _treeCardMaterial = CreateAtlasMaterialFromCandidate(best, _treeAtlasTexture, "Donegal Horizon Fixed Tree Cards"); _treeAtlasShader = (((Object)(object)_treeCardMaterial.shader != (Object)null) ? ((Object)_treeCardMaterial.shader).name : "none"); ValidateAndReportTreeCardCutoutMaterial(); _treeAtlasStatus = (_treeCardCutoutMaterialValid ? "ready" : "waiting for depth-writing alpha-cutout material"); if (_treeCardCutoutMaterialValid) { _lastAtlasMaterialError = "none"; flag5 = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Tree atlas material created using live Valheim material fallback. Source material: " + ((Object)best).name + ". " + DescribeAtlasMaterial(_treeCardMaterial))); } } if (flag2) { _canopyCardMaterial = CreateAtlasMaterialFromCandidate(best, _canopyAtlasTexture, "Donegal Horizon Canopy/Treeline Cards"); _canopyAtlasShader = (((Object)(object)_canopyCardMaterial.shader != (Object)null) ? ((Object)_canopyCardMaterial.shader).name : "none"); _canopyAtlasStatus = "ready"; _lastAtlasMaterialError = "none"; flag5 = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Canopy atlas material created using live Valheim material fallback. Source material: " + ((Object)best).name + ". " + DescribeAtlasMaterial(_canopyCardMaterial))); } if (flag3) { _mountainBiomeCardMaterial = CreateAtlasMaterialFromCandidate(best, _mountainBiomeAtlasTexture, "Donegal Horizon Mountain Biome Cards"); _mountainBiomeAtlasShader = (((Object)(object)_mountainBiomeCardMaterial.shader != (Object)null) ? ((Object)_mountainBiomeCardMaterial.shader).name : "none"); _mountainBiomeAtlasStatus = "ready"; _lastAtlasMaterialError = "none"; flag5 = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Mountain biome atlas material created using live Valheim material fallback. Shader: " + _mountainBiomeAtlasShader + ". Source material: " + ((Object)best).name + ".")); } if (flag4) { _swampBiomeCardMaterial = CreateAtlasMaterialFromCandidate(best, _swampBiomeAtlasTexture, "Donegal Horizon Swamp Biome Cards"); _swampBiomeAtlasShader = (((Object)(object)_swampBiomeCardMaterial.shader != (Object)null) ? ((Object)_swampBiomeCardMaterial.shader).name : "none"); _swampBiomeAtlasStatus = "ready"; _lastAtlasMaterialError = "none"; flag5 = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Swamp biome atlas material created using live Valheim material fallback. Shader: " + _swampBiomeAtlasShader + ". Source material: " + ((Object)best).name + ".")); } if (flag5) { ReportForestAtlasMaterialsReadyIfComplete(); ApplyHorizonClarityToCardMaterials(); int count = _forestTiles.Count; if (count > 0) { InvalidateAllForestTiles("atlas material became available", immediate: false); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[New Horizons Treelines] PROVISIONAL FOREST TILES REQUEUED: " + count)); } BeginForestOnlyRebuild("atlas material became available"); } } private static bool TryFindAtlasFallbackCandidate(out Material best, out string failure) { best = null; failure = "No loaded Valheim foliage/cutout material matched."; Material[] array = Resources.FindObjectsOfTypeAll(); int num = int.MinValue; foreach (Material val in array) { int num2 = ScoreAtlasFallbackCandidate(val); if (num2 > num) { num = num2; best = val; } } if ((Object)(object)best == (Object)null || num <= 0) { failure = "No compatible loaded vegetation material was available yet."; return false; } return true; } private static Material CreateAtlasMaterialFromCandidate(Material candidate, Texture2D texture, string cloneName) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown Material val = new Material(candidate); ((Object)val).name = cloneName + " (clone from " + ((Object)candidate).name + ")"; ApplyAtlasMaterialProperties(val, texture, forceCutoutDefaults: true); return val; } private static string DescribeAtlasMaterial(Material material) { if ((Object)(object)material == (Object)null) { return "none"; } float num = (material.HasProperty("_Cutoff") ? material.GetFloat("_Cutoff") : (-1f)); string text = (((Object)(object)material.shader != (Object)null) ? ((Object)material.shader).name : "none"); bool flag = MaterialUsesCutoutSemantics(material); return "shader " + text + ", cutoff " + num.ToString("F2", CultureInfo.InvariantCulture) + ", queue " + material.renderQueue + ", alpha clip " + (flag ? "active" : "inactive") + " (keyword " + (material.IsKeywordEnabled("_ALPHATEST_ON") ? "on" : "not used") + "), motion props zeroed " + _lastMotionPropsZeroed; } private static bool MaterialUsesCutoutSemantics(Material material) { if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null) { return false; } string text = ((Object)material.shader).name.ToLowerInvariant(); bool flag = text.Contains("vegetation") || text.Contains("cutout") || text.Contains("alphatest") || text.Contains("alpha test"); bool flag2 = material.HasProperty("_Cutoff") && material.GetFloat("_Cutoff") > 0.001f; if (!material.IsKeywordEnabled("_ALPHATEST_ON")) { return flag2 && flag; } return true; } private void ValidateAndReportTreeCardCutoutMaterial() { //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) Material treeCardMaterial = _treeCardMaterial; if ((Object)(object)treeCardMaterial == (Object)null) { _treeCardCutoutMaterialValid = false; _treeCardCutoutMaterialDetail = "tree card material unavailable"; return; } ApplyAtlasMaterialProperties(treeCardMaterial, _treeAtlasTexture, forceCutoutDefaults: true); string text = (((Object)(object)treeCardMaterial.shader != (Object)null) ? ((Object)treeCardMaterial.shader).name : "none"); bool flag = (treeCardMaterial.HasProperty("_ZWrite") ? (treeCardMaterial.GetInt("_ZWrite") != 0) : (treeCardMaterial.renderQueue == 2450)); int num = (treeCardMaterial.HasProperty("_ZTest") ? treeCardMaterial.GetInt("_ZTest") : 4); int num2 = ((!treeCardMaterial.HasProperty("_SrcBlend")) ? 1 : treeCardMaterial.GetInt("_SrcBlend")); int num3 = (treeCardMaterial.HasProperty("_DstBlend") ? treeCardMaterial.GetInt("_DstBlend") : 0); int num4 = (treeCardMaterial.HasProperty("_Cull") ? treeCardMaterial.GetInt("_Cull") : 0); float num5 = (treeCardMaterial.HasProperty("_Cutoff") ? treeCardMaterial.GetFloat("_Cutoff") : (-1f)); bool flag2 = MaterialUsesCutoutSemantics(treeCardMaterial); _treeCardCutoutMaterialValid = treeCardMaterial.renderQueue == 2450 && flag && num == 4 && num2 == 1 && num3 == 0 && flag2 && num5 >= 0.39f && num4 == 0; _treeCardCutoutMaterialDetail = "shader=" + text + " queue=" + treeCardMaterial.renderQueue + " ZWrite=" + (flag ? "On" : "Off") + " ZTest=" + ((object)(CompareFunction)num/*cast due to .constrained prefix*/).ToString() + " blend=" + ((object)(BlendMode)num2/*cast due to .constrained prefix*/).ToString() + "/" + ((object)(BlendMode)num3/*cast due to .constrained prefix*/).ToString() + " alphaClip=" + (flag2 ? "active" : "inactive") + " keyword=" + (treeCardMaterial.IsKeywordEnabled("_ALPHATEST_ON") ? "on" : "shader-semantic") + " cutoff=" + num5.ToString("F2", CultureInfo.InvariantCulture) + " cull=" + ((object)(CullMode)num4/*cast due to .constrained prefix*/).ToString(); if (_treeCardCutoutMaterialValid && !_treeCardCutoutMaterialValidLogged) { _treeCardCutoutMaterialValidLogged = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("TREE CARD CUTOUT MATERIAL VALID | " + _treeCardCutoutMaterialDetail)); } } private static int ScoreAtlasFallbackCandidate(Material material) { if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null) { return int.MinValue; } if (!material.HasProperty("_MainTex")) { return int.MinValue; } string text = (((Object)material).name + " " + ((Object)material.shader).name).ToLowerInvariant(); if (text.Contains("sprite") || text.Contains("terrain") || text.Contains("water") || text.Contains("sky") || text.Contains("particle") || text.Contains("ui") || text.Contains("font") || text.Contains("text") || text.Contains("minimap") || text.Contains("cloud")) { return int.MinValue; } if (text.Contains("log") || text.Contains("bark") || text.Contains("trunk") || text.Contains("stump") || text.Contains("wood") || text.Contains("rock") || text.Contains("stone")) { return int.MinValue; } if (!material.HasProperty("_Cutoff") && !text.Contains("cutout") && !text.Contains("alphatest")) { return int.MinValue; } int num = 0; if (text.Contains("vegetation")) { num += 40; } if (text.Contains("foliage")) { num += 35; } if (text.Contains("plant")) { num += 28; } if (text.Contains("tree")) { num += 28; } if (text.Contains("leaf") || text.Contains("leaves")) { num += 26; } if (text.Contains("bush")) { num += 20; } if (text.Contains("branch")) { num += 24; } if (text.Contains("needle")) { num += 18; } if (text.Contains("beech") || text.Contains("oak") || text.Contains("pine") || text.Contains("fir") || text.Contains("birch")) { num += 14; } if (text.Contains("cutout")) { num += 18; } if (text.Contains("alpha")) { num += 12; } if (material.HasProperty("_Cutoff")) { num += 16; } if (material.HasProperty("_ZWrite")) { num += ((material.GetInt("_ZWrite") != 0) ? 8 : (-8)); } if (material.renderQueue >= 2400 && material.renderQueue <= 2500) { num += 8; } if (material.renderQueue >= 3000) { num -= 20; } return num; } private static void ApplyAtlasMaterialProperties(Material material, Texture2D texture, bool forceCutoutDefaults) { //IL_0029: 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_0056: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null) { return; } if (material.HasProperty("_MainTex")) { material.SetTexture("_MainTex", (Texture)(object)texture); material.SetTextureScale("_MainTex", Vector2.one); material.SetTextureOffset("_MainTex", Vector2.zero); } if (material.HasProperty("_Color")) { material.SetColor("_Color", Color.white); material.color = Color.white; } if (material.HasProperty("_Color2")) { material.SetColor("_Color2", Color.white); } if (material.HasProperty("_TintColor")) { material.SetColor("_TintColor", Color.white); } if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", Color.white); } ClearAtlasInheritedTexture(material, "_BumpMap"); ClearAtlasInheritedTexture(material, "_NormalMap"); ClearAtlasInheritedTexture(material, "_DetailNormalMap"); ClearAtlasInheritedTexture(material, "_DetailAlbedoMap"); ClearAtlasInheritedTexture(material, "_MetallicGlossMap"); ClearAtlasInheritedTexture(material, "_SpecGlossMap"); ClearAtlasInheritedTexture(material, "_OcclusionMap"); ClearAtlasInheritedTexture(material, "_EmissionMap"); ClearAtlasInheritedTexture(material, "_MaskMap"); ClearAtlasInheritedTexture(material, "_MaskTex"); material.DisableKeyword("_NORMALMAP"); material.DisableKeyword("_DETAIL_MULX2"); material.DisableKeyword("_METALLICGLOSSMAP"); material.DisableKeyword("_SPECGLOSSMAP"); material.DisableKeyword("_EMISSION"); if (material.HasProperty("_BumpScale")) { material.SetFloat("_BumpScale", 0f); } if (material.HasProperty("_OcclusionStrength")) { material.SetFloat("_OcclusionStrength", 0f); } if (material.HasProperty("_EmissionColor")) { material.SetColor("_EmissionColor", Color.black); } if (material.HasProperty("_Cutoff")) { material.SetFloat("_Cutoff", 0.4f); } if (material.HasProperty("_Mode")) { material.SetFloat("_Mode", 1f); } material.EnableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.SetOverrideTag("RenderType", "TransparentCutout"); if (material.HasProperty("_Glossiness")) { material.SetFloat("_Glossiness", 0f); } if (material.HasProperty("_Metallic")) { material.SetFloat("_Metallic", 0f); } if (material.HasProperty("_SpecColor")) { material.SetColor("_SpecColor", Color.black); } if (forceCutoutDefaults) { material.renderQueue = 2450; if (material.HasProperty("_ZWrite")) { material.SetInt("_ZWrite", 1); } if (material.HasProperty("_ZTest")) { material.SetInt("_ZTest", 4); } if (material.HasProperty("_SrcBlend")) { material.SetInt("_SrcBlend", 1); } if (material.HasProperty("_DstBlend")) { material.SetInt("_DstBlend", 0); } if (material.HasProperty("_BlendOp")) { material.SetInt("_BlendOp", 0); } } if (material.HasProperty("_Cull")) { material.SetInt("_Cull", 0); } SuppressAtlasWind(material); } private static void ClearAtlasInheritedTexture(Material material, string propertyName) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null || !material.HasProperty(propertyName)) { return; } try { int num = material.shader.FindPropertyIndex(propertyName); if (num >= 0 && (int)material.shader.GetPropertyType(num) == 4) { material.SetTexture(propertyName, (Texture)null); } } catch { } } private static void SuppressAtlasWind(Material material) { //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Invalid comparison between Unknown and I4 //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Invalid comparison between Unknown and I4 //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Invalid comparison between Unknown and I4 //IL_0269: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null) { return; } string[] array = new string[37] { "_Wind", "_WindOn", "_WindStrength", "_WindIntensity", "_WindAmount", "_WindSpeed", "_WindScale", "_WindBend", "_Bend", "_Bending", "_BendScale", "_TreeWind", "_LeafWind", "_BranchWind", "_Waving", "_WavingSpeed", "_WavingAmount", "_WavingStrength", "_Interaction", "_InteractionStrength", "_SwaySpeed", "_SwayDistance", "_SwayAmount", "_RippleSpeed", "_RippleDistance", "_RippleFreq", "_RippleFrequency", "_PushDistance", "_PushFlexibility", "_MotionSpeed", "_MotionAmount", "_WaveSpeed", "_WaveAmount", "_WaveScale", "_ShakeSpeed", "_ShakeAmount", "_Flexibility" }; for (int i = 0; i < array.Length; i++) { if (material.HasProperty(array[i])) { material.SetFloat(array[i], 0f); } } string[] array2 = new string[4] { "_WindDir", "_WindDirection", "_GlobalWind", "_WindVector" }; for (int j = 0; j < array2.Length; j++) { if (material.HasProperty(array2[j])) { material.SetVector(array2[j], Vector4.zero); } } material.DisableKeyword("WIND_ON"); material.DisableKeyword("_WIND_ON"); material.DisableKeyword("ENABLE_WIND"); material.DisableKeyword("VEGETATION_WIND"); _lastMotionPropsZeroed = 0; try { Shader shader = material.shader; if ((Object)(object)shader != (Object)null) { int propertyCount = shader.GetPropertyCount(); for (int k = 0; k < propertyCount; k++) { string propertyName = shader.GetPropertyName(k); if (IsMotionPropertyName(propertyName)) { ShaderPropertyType propertyType = shader.GetPropertyType(k); if ((int)propertyType == 2 || (int)propertyType == 3) { material.SetFloat(propertyName, 0f); _lastMotionPropsZeroed++; } else if ((int)propertyType == 1) { material.SetVector(propertyName, Vector4.zero); _lastMotionPropsZeroed++; } } } } string[] shaderKeywords = material.shaderKeywords; if (shaderKeywords == null) { return; } for (int l = 0; l < shaderKeywords.Length; l++) { string text = ((shaderKeywords[l] != null) ? shaderKeywords[l].ToUpperInvariant() : ""); if (text.Contains("WIND") || text.Contains("SWAY") || text.Contains("RIPPLE") || text.Contains("PUSH") || text.Contains("WAVE") || text.Contains("MOTION")) { material.DisableKeyword(shaderKeywords[l]); } } } catch (Exception) { } } private static bool IsMotionPropertyName(string propertyName) { if (string.IsNullOrEmpty(propertyName)) { return false; } string text = propertyName.ToLowerInvariant(); if (!text.Contains("wind") && !text.Contains("sway") && !text.Contains("ripple") && !text.Contains("push") && !text.Contains("wave") && !text.Contains("bend") && !text.Contains("flutter") && !text.Contains("motion") && !text.Contains("wiggle") && !text.Contains("shake") && !text.Contains("breeze") && !text.Contains("flex") && !text.Contains("gust")) { return text.Contains("turbul"); } return true; } private static Shader FindShader(params string[] names) { for (int i = 0; i < names.Length; i++) { Shader val = Shader.Find(names[i]); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static void ConfigureRenderer(MeshRenderer renderer) { ((Renderer)renderer).enabled = true; ((Renderer)renderer).receiveShadows = false; ((Renderer)renderer).shadowCastingMode = (ShadowCastingMode)0; ((Component)renderer).gameObject.layer = 0; } private void ConfigureTreeCardRenderer(MeshRenderer renderer) { if (!((Object)(object)renderer == (Object)null)) { ConfigureRenderer(renderer); ((Renderer)renderer).motionVectorGenerationMode = (MotionVectorGenerationMode)2; ((Renderer)renderer).lightProbeUsage = (LightProbeUsage)0; ((Renderer)renderer).reflectionProbeUsage = (ReflectionProbeUsage)0; ((Renderer)renderer).allowOcclusionWhenDynamic = true; _treeRendererPropertiesDirty = true; } } private static GameObject CreateMeshObject(string name, Transform parent, out MeshFilter filter, out MeshRenderer renderer) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown GameObject val = new GameObject(name); val.layer = 0; val.transform.SetParent(parent, false); filter = val.AddComponent(); renderer = val.AddComponent(); return val; } private static Color ParseColor(string value, Color fallback) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_008a: 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) if (string.IsNullOrEmpty(value)) { return fallback; } string[] array = value.Split(','); if (array.Length < 3) { return fallback; } if (!float.TryParse(array[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return fallback; } if (!float.TryParse(array[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return fallback; } if (!float.TryParse(array[2].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { return fallback; } return new Color(Mathf.Clamp01(result), Mathf.Clamp01(result2), Mathf.Clamp01(result3), 1f); } private float BiomeForestMultiplier(Biome biome) { //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_000f: 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_001b: 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_003a: 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_0059: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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_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) if ((biome & 0x100) != 0) { return 0f; } if ((biome & 0x20) != 0) { return 0f; } if ((biome & 8) != 0) { if (_blackForestDistantTreeDensity == null) { return 1.4f; } return _blackForestDistantTreeDensity.Value; } if ((biome & 1) != 0) { if (_meadowsDistantTreeDensity == null) { return 1.1f; } return _meadowsDistantTreeDensity.Value; } if ((biome & 2) != 0) { if (_enableSwampTreeCards == null || _enableSwampTreeCards.Value) { if (_swampDistantTreeDensity == null) { return 1.2f; } return _swampDistantTreeDensity.Value; } return 0f; } if ((biome & 0x200) != 0) { if (_mistlandsDistantTreeDensity == null) { return 0.55f; } return _mistlandsDistantTreeDensity.Value; } if ((biome & 4) != 0) { if (_mountainDistantTreeDensity == null) { return 0.65f; } return _mountainDistantTreeDensity.Value; } if ((biome & 0x10) != 0) { if (_plainsDistantTreeDensity == null) { return 0.25f; } return _plainsDistantTreeDensity.Value; } if ((biome & 0x40) != 0) { if (_deepNorthDistantTreeDensity == null) { return 0.35f; } return _deepNorthDistantTreeDensity.Value; } return 0.25f; } private float DistributedDensityForBiome(Biome biome) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_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_0058: 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_0078: 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_0098: 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) if ((biome & 0x20) != 0 || (biome & 0x100) != 0) { return 0f; } if ((biome & 8) != 0) { if (_blackForestDistributedDensity == null) { return 2f; } return _blackForestDistributedDensity.Value; } if ((biome & 1) != 0) { if (_meadowsDistributedDensity == null) { return 1.3f; } return _meadowsDistributedDensity.Value; } if ((biome & 4) != 0 || (biome & 0x40) != 0) { if (_mountainDistributedDensity == null) { return 1.15f; } return _mountainDistributedDensity.Value; } if ((biome & 0x10) != 0) { if (_plainsDistributedDensity == null) { return 0.25f; } return _plainsDistributedDensity.Value; } if ((biome & 2) != 0) { if (_enableSwampTreeCards == null || _enableSwampTreeCards.Value) { if (_swampDistributedDensity == null) { return 1f; } return _swampDistributedDensity.Value; } return 0f; } return 1f; } private float BiomeCanopyDensityMultiplier(Biome biome) { //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_0009: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) if ((biome & 0x100) != 0 || (biome & 0x20) != 0) { return 0f; } if ((biome & 8) != 0) { if (_blackForestDistantCanopyDensity == null) { return 1.35f; } return _blackForestDistantCanopyDensity.Value; } if ((biome & 1) != 0) { if (_meadowsDistantCanopyDensity == null) { return 1f; } return _meadowsDistantCanopyDensity.Value; } if ((biome & 2) != 0) { if (_enableSwampTreeCards == null || _enableSwampTreeCards.Value) { if (_swampDistantCanopyDensity == null) { return 1.05f; } return _swampDistantCanopyDensity.Value; } return 0f; } if ((biome & 0x200) != 0) { if (_mistlandsDistantCanopyDensity == null) { return 0.4f; } return _mistlandsDistantCanopyDensity.Value; } if ((biome & 4) != 0) { if (_mountainDistantCanopyDensity == null) { return 0.45f; } return _mountainDistantCanopyDensity.Value; } if ((biome & 0x10) != 0) { if (_plainsDistantCanopyDensity == null) { return 0.1f; } return _plainsDistantCanopyDensity.Value; } return 1f; } private static void AddBiomeCluster(List vertices, List triangles, float x, float ground, float z, float height, Biome biome, int seed) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_003f: 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_005c: 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) if ((biome & 2) != 0) { AddLowScrub(vertices, triangles, x, ground, z, height * 0.55f, seed); } else if ((biome & 0x10) != 0) { AddLowScrub(vertices, triangles, x, ground, z, height * 0.42f, seed); } else if ((biome & 4) != 0 || (biome & 0x40) != 0) { AddConifer(vertices, triangles, x, ground, z, height * 0.85f, seed); } else if ((biome & 8) != 0 || Hash01(seed ^ 0x115F) < 0.7f) { AddConifer(vertices, triangles, x, ground, z, height, seed); } else { AddBroadleaf(vertices, triangles, x, ground, z, height, seed); } } private static void AddConifer(List vertices, List triangles, float x, float ground, float z, float height, int seed) { float height2 = height * 0.12f; float num = (Hash01(seed ^ 0x6F1) - 0.5f) * height * 0.04f; float num2 = (Hash01(seed ^ 0xA97) - 0.5f) * height * 0.04f; AddTaperedCone(vertices, triangles, x, ground, z, height * 0.055f, height * 0.038f, height2, 5); AddTaperedCone(vertices, triangles, x + num * 0.2f, ground + height * 0.13f, z + num2 * 0.2f, height * 0.22f, height * 0.065f, height * 0.42f, 6); AddTaperedCone(vertices, triangles, x + num * 0.5f, ground + height * 0.34f, z + num2 * 0.5f, height * 0.17f, height * 0.038f, height * 0.4f, 6); AddTaperedCone(vertices, triangles, x + num * 0.8f, ground + height * 0.56f, z + num2 * 0.8f, height * 0.12f, 0.006f, height * 0.36f, 6); } private static void AddBroadleaf(List vertices, List triangles, float x, float ground, float z, float height, int seed) { AddTaperedCone(vertices, triangles, x, ground, z, height * 0.045f, height * 0.03f, height * 0.24f, 5); AddOctahedralCrown(vertices, triangles, x, ground + height * 0.52f, z, height * 0.28f, height * 0.34f, height * 0.28f); AddOctahedralCrown(vertices, triangles, x + (Hash01(seed ^ 0x1843) - 0.5f) * height * 0.12f, ground + height * 0.68f, z + (Hash01(seed ^ 0x1EEF) - 0.5f) * height * 0.12f, height * 0.2f, height * 0.26f, height * 0.2f); } private static void AddLowScrub(List vertices, List triangles, float x, float ground, float z, float height, int seed) { AddOctahedralCrown(vertices, triangles, x, ground + height * 0.24f, z, height * 0.34f, height * 0.24f, height * 0.3f); if (Hash01(seed ^ 0x22E5) > 0.45f) { AddOctahedralCrown(vertices, triangles, x + (Hash01(seed ^ 0x3DF) - 0.5f) * height * 0.55f, ground + height * 0.18f, z + (Hash01(seed ^ 0xE9) - 0.5f) * height * 0.55f, height * 0.22f, height * 0.18f, height * 0.22f); } } private static void AddTaperedCone(List vertices, List triangles, float x, float y, float z, float bottomRadius, float topRadius, float height, int sides) { //IL_003a: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) int count = vertices.Count; for (int i = 0; i < sides; i++) { float num = (float)i * MathF.PI * 2f / (float)sides; vertices.Add(new Vector3(x + Mathf.Cos(num) * bottomRadius, y, z + Mathf.Sin(num) * bottomRadius)); } for (int j = 0; j < sides; j++) { float num2 = (float)j * MathF.PI * 2f / (float)sides; vertices.Add(new Vector3(x + Mathf.Cos(num2) * topRadius, y + height, z + Mathf.Sin(num2) * topRadius)); } int count2 = vertices.Count; vertices.Add(new Vector3(x, y, z)); int count3 = vertices.Count; vertices.Add(new Vector3(x, y + height, z)); for (int k = 0; k < sides; k++) { int num3 = (k + 1) % sides; AddQuadDoubleSided(triangles, count + k, count + num3, count + sides + num3, count + sides + k); AddTriangleDoubleSided(triangles, count2, count + num3, count + k); AddTriangleDoubleSided(triangles, count3, count + sides + k, count + sides + num3); } } private static void AddOctahedralCrown(List vertices, List triangles, float x, float y, float z, float radiusX, float radiusY, float radiusZ) { //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_0033: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) int count = vertices.Count; vertices.Add(new Vector3(x, y + radiusY, z)); vertices.Add(new Vector3(x + radiusX, y, z)); vertices.Add(new Vector3(x, y, z + radiusZ)); vertices.Add(new Vector3(x - radiusX, y, z)); vertices.Add(new Vector3(x, y, z - radiusZ)); vertices.Add(new Vector3(x, y - radiusY, z)); AddTriangleDoubleSided(triangles, count, count + 1, count + 2); AddTriangleDoubleSided(triangles, count, count + 2, count + 3); AddTriangleDoubleSided(triangles, count, count + 3, count + 4); AddTriangleDoubleSided(triangles, count, count + 4, count + 1); AddTriangleDoubleSided(triangles, count + 5, count + 2, count + 1); AddTriangleDoubleSided(triangles, count + 5, count + 3, count + 2); AddTriangleDoubleSided(triangles, count + 5, count + 4, count + 3); AddTriangleDoubleSided(triangles, count + 5, count + 1, count + 4); } private static void AddAtlasCutoutQuad(List vertices, List uvs, List triangles, Vector3 bottomLeft, Vector3 topLeft, Vector3 topRight, Vector3 bottomRight, Vector2 uvBottomLeft, Vector2 uvTopLeft, Vector2 uvTopRight, Vector2 uvBottomRight) { //IL_0008: 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_0017: 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_0027: 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_0037: 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) int count = vertices.Count; vertices.Add(bottomLeft); vertices.Add(topLeft); vertices.Add(topRight); vertices.Add(bottomRight); uvs.Add(uvBottomLeft); uvs.Add(uvTopLeft); uvs.Add(uvTopRight); uvs.Add(uvBottomRight); triangles.Add(count); triangles.Add(count + 1); triangles.Add(count + 2); triangles.Add(count); triangles.Add(count + 2); triangles.Add(count + 3); } private static void AddTriangleDoubleSided(List triangles, int a, int b, int c) { triangles.Add(a); triangles.Add(b); triangles.Add(c); triangles.Add(c); triangles.Add(b); triangles.Add(a); } private static void AddQuadDoubleSided(List triangles, int a, int b, int c, int d) { AddTriangleDoubleSided(triangles, a, b, c); AddTriangleDoubleSided(triangles, a, c, d); } private static int Hash(int x, int z, int salt) { int num = salt; num = num * 486187739 + x; num = num * 486187739 + z; num ^= num >> 13; num *= 1274126177; return num ^ (num >> 16); } private static int StableForestCardRecord(int treeSeed, float worldX, float worldZ, int atlasIndex, Biome biome) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected I4, but got Unknown return HashCombine(treeSeed, HashCombine(Mathf.RoundToInt(worldX * 100f), Mathf.RoundToInt(worldZ * 100f), atlasIndex), (int)biome); } private static int HashCombine(int a, int b, int c) { int num = a; num = (num * 16777619) ^ b; num = (num * 16777619) ^ c; return num ^ (num >> 15); } private static int StableStringSeed(string value) { int num = -2128831035; if (!string.IsNullOrEmpty(value)) { for (int i = 0; i < value.Length; i++) { num = (num ^ value[i]) * 16777619; } } return num; } private static float Hash01(int value) { uint num = (uint)value; num ^= num >> 17; num *= 3982152891u; num ^= num >> 11; num *= 2890668881u; num ^= num >> 15; num *= 830770091; num ^= num >> 14; return (float)(num & 0xFFFFFF) / 16777215f; } private static Dictionary ReadSimpleConfig(string path) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0 && text[0] != '#' && text[0] != '[') { int num = text.IndexOf('='); if (num > 0) { dictionary[text.Substring(0, num).Trim()] = text.Substring(num + 1).Trim(); } } } return dictionary; } private static string ReadConfigValue(string path, string key) { try { if (!File.Exists(path)) { return ""; } Dictionary dictionary = ReadSimpleConfig(path); string value; return dictionary.TryGetValue(key, out value) ? value : ""; } catch { return ""; } } private static float GetConfigFloat(Dictionary values, string key, float fallback) { if (!TryGetConfigFloatValue(values, key, out var parsed)) { return fallback; } return parsed; } private static bool TryGetConfigFloatValue(Dictionary values, string key, out float parsed) { if (values.TryGetValue(key, out var value) && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out parsed)) { return true; } parsed = 0f; return false; } private static bool TryGetFirstConfigFloat(Dictionary values, out float parsed, out string key, params string[] keys) { for (int i = 0; i < keys.Length; i++) { if (TryGetConfigFloatValue(values, keys[i], out parsed)) { key = keys[i]; return true; } } parsed = 0f; key = ""; return false; } private static string ResolvePath(string path, string fallbackRoot) { if (Path.IsPathRooted(path)) { return path; } return Path.Combine(fallbackRoot, path); } private static Texture2D LoadPng(string path, FilterMode filterMode, bool generateMipmaps = false) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) byte[] array = File.ReadAllBytes(path); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, generateMipmaps, false); if (!ImageConversion.LoadImage(val, array, false)) { Object.Destroy((Object)(object)val); throw new InvalidOperationException("Could not decode PNG: " + path); } ((Object)val).name = Path.GetFileName(path); ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = filterMode; if (generateMipmaps) { val.Apply(true, false); ((Texture)val).mipMapBias = -0.2f; ((Texture)val).anisoLevel = 1; } return val; } private static float SamplePixels(Color32[] pixels, int width, int height, float u, float vTopDown) { if (pixels == null || pixels.Length == 0 || width <= 0 || height <= 0) { return 0f; } float num = Mathf.Clamp01(u) * (float)(width - 1); float num2 = Mathf.Clamp01(vTopDown) * (float)(height - 1); int num3 = Mathf.Clamp(Mathf.FloorToInt(num), 0, width - 1); int num4 = Mathf.Clamp(Mathf.FloorToInt(num2), 0, height - 1); int x = Mathf.Min(num3 + 1, width - 1); int yTopDown = Mathf.Min(num4 + 1, height - 1); float num5 = num - (float)num3; float num6 = num2 - (float)num4; float num7 = Mathf.Lerp(ReadRedTopDown(pixels, width, height, num3, num4), ReadRedTopDown(pixels, width, height, x, num4), num5); float num8 = Mathf.Lerp(ReadRedTopDown(pixels, width, height, num3, yTopDown), ReadRedTopDown(pixels, width, height, x, yTopDown), num5); return Mathf.Lerp(num7, num8, num6); } private static Color SampleTextureColourTopDown(Color32[] pixels, int width, int height, float u, float vTopDown) { //IL_000f: 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_005b: Unknown result type (might be due to invalid IL or missing references) if (pixels == null || pixels.Length == 0 || width <= 0 || height <= 0) { return Color.black; } int num = Mathf.Clamp(Mathf.RoundToInt(Mathf.Clamp01(u) * (float)(width - 1)), 0, width - 1); int num2 = Mathf.Clamp(Mathf.RoundToInt(Mathf.Clamp01(vTopDown) * (float)(height - 1)), 0, height - 1); int num3 = height - 1 - num2; return Color32.op_Implicit(pixels[num3 * width + num]); } private static float ReadRedTopDown(Color32[] pixels, int width, int height, int x, int yTopDown) { int num = height - 1 - Mathf.Clamp(yTopDown, 0, height - 1); int num2 = num * width + Mathf.Clamp(x, 0, width - 1); if (num2 < 0 || num2 >= pixels.Length) { return 0f; } return (float)(int)pixels[num2].r / 255f; } private static string FileHashShort(string path) { byte[] array = File.ReadAllBytes(path); uint num = 2166136261u; for (int i = 0; i < array.Length; i++) { num ^= array[i]; num *= 16777619; } return num.ToString("X8", CultureInfo.InvariantCulture); } private static string SafeFileName(string value) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); for (int i = 0; i < invalidFileNameChars.Length; i++) { value = value.Replace(invalidFileNameChars[i], '_'); } return value.Replace(' ', '_'); } private static long TileKey(int x, int z) { return ((long)x << 32) ^ (uint)z; } }