Decompiled source of WeatherOverhaul v1.0.5

WeatherOverhaul.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Collections;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.PostProcessing;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityStandardAssets.ImageEffects;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("WeatherOverhaul")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.5.0")]
[assembly: AssemblyInformationalVersion("1.0.5+652c2aa0cc3d99505eb206f8e6bfbced6f5e4d36")]
[assembly: AssemblyProduct("WeatherOverhaul")]
[assembly: AssemblyTitle("WeatherOverhaul")]
[assembly: AssemblyVersion("1.0.5.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace WeatherOverhaul
{
	internal static class BiomeList
	{
		private static readonly Dictionary<string, int> Values = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
		{
			{ "Meadows", 1 },
			{ "Swamp", 2 },
			{ "Mountain", 4 },
			{ "BlackForest", 8 },
			{ "Plains", 16 },
			{ "AshLands", 32 },
			{ "DeepNorth", 64 },
			{ "Ocean", 256 },
			{ "Mistlands", 512 }
		};

		public static int Parse(string list, List<string> unknown)
		{
			if (string.IsNullOrEmpty(list))
			{
				return 0;
			}
			int num = 0;
			string[] array = list.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length != 0)
				{
					if (Values.TryGetValue(text, out var value))
					{
						num |= value;
					}
					else
					{
						unknown.Add(text);
					}
				}
			}
			return num;
		}
	}
	internal static class BiomeStorms
	{
		public const int Swamp = 2;

		public const int Plains = 16;

		public static float PlainsShare;

		public static float SwampShare;

		public static bool Adds(int worldSeed, long period, int biome, in EnvDescriptor e)
		{
			//IL_0047: 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 (e.HasLightning || WeatherBlend.RainOf(in e) < 0.5f)
			{
				return false;
			}
			float num = biome switch
			{
				2 => SwampShare, 
				16 => PlainsShare, 
				_ => 0f, 
			};
			if (!(num > 0f))
			{
				return false;
			}
			Random val = DayVariations.Draws(worldSeed, period, e.Name, DayVariations.Use.Storms);
			return ((Random)(ref val)).NextFloat() < num;
		}

		public static EnvDescriptor Apply(int worldSeed, long period, int biome, EnvDescriptor e)
		{
			if (Adds(worldSeed, period, biome, in e))
			{
				e.HasLightning = true;
			}
			return e;
		}
	}
	internal sealed class CameraPasses<TCamera, TPass> where TCamera : class where TPass : class
	{
		private readonly Action<TCamera, TPass> _attach;

		private readonly Action<TCamera, TPass> _detach;

		private readonly Func<TCamera, bool> _alive;

		private readonly List<TCamera> _cameras = new List<TCamera>();

		private readonly List<TPass> _passes = new List<TPass>();

		public CameraPasses(Action<TCamera, TPass> attach, Action<TCamera, TPass> detach, Func<TCamera, bool> alive)
		{
			_attach = attach;
			_detach = detach;
			_alive = alive;
		}

		public void Seen(TCamera camera)
		{
			Prune();
			if (_cameras.Contains(camera))
			{
				return;
			}
			_cameras.Add(camera);
			foreach (TPass pass in _passes)
			{
				_attach(camera, pass);
			}
		}

		public void Forget(TCamera camera)
		{
			Prune();
			if (!_cameras.Remove(camera))
			{
				return;
			}
			foreach (TPass pass in _passes)
			{
				_detach(camera, pass);
			}
		}

		public void Add(TPass pass)
		{
			Prune();
			if (_passes.Contains(pass))
			{
				return;
			}
			_passes.Add(pass);
			foreach (TCamera camera in _cameras)
			{
				_attach(camera, pass);
			}
		}

		public int RemoveAll(Predicate<TPass> match)
		{
			Prune();
			int num = 0;
			for (int num2 = _passes.Count - 1; num2 >= 0; num2--)
			{
				if (match(_passes[num2]))
				{
					foreach (TCamera camera in _cameras)
					{
						_detach(camera, _passes[num2]);
					}
					_passes.RemoveAt(num2);
					num++;
				}
			}
			return num;
		}

		public void Clear()
		{
			Prune();
			foreach (TCamera camera in _cameras)
			{
				foreach (TPass pass in _passes)
				{
					_detach(camera, pass);
				}
			}
			_cameras.Clear();
			_passes.Clear();
		}

		private void Prune()
		{
			for (int num = _cameras.Count - 1; num >= 0; num--)
			{
				if (!_alive(_cameras[num]))
				{
					_cameras.RemoveAt(num);
				}
			}
		}
	}
	public struct DayVariation
	{
		public float CloudCover;

		public float CloudType;

		public float SunsetWarmth;

		public float PrecipitationScale;

		public float MorningMist;
	}
	internal static class DayVariations
	{
		internal enum Use
		{
			Day,
			DayAir,
			Look,
			Storms,
			CumulusDrift,
			CongestusDrift,
			StrikesFar,
			StrikesNear,
			CloudFlashes
		}

		public static DayVariation For(int worldSeed, int day, string environment)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Random val = Draws(worldSeed, day, environment, Use.Day);
			float num = ((Random)(ref val)).NextFloat();
			float cloudType = ((Random)(ref val)).NextFloat();
			float sunsetWarmth = ((Random)(ref val)).NextFloat();
			float num2 = ((Random)(ref val)).NextFloat();
			float num3 = ((Random)(ref val)).NextFloat();
			return new DayVariation
			{
				CloudCover = 0.25f + 0.5f * num,
				CloudType = cloudType,
				SunsetWarmth = sunsetWarmth,
				PrecipitationScale = 0.7f + 0.6f * num2,
				MorningMist = ((num3 < 0.4f) ? 1f : 0f)
			};
		}

		public static float Air(int worldSeed, int day)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Random val = Draws(worldSeed, day, null, Use.DayAir);
			return ((Random)(ref val)).NextFloat();
		}

		internal static Random Draws(int worldSeed, long key, string environment, Use use)
		{
			//IL_0016: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			int num = ((environment != null) ? StringExtensionMethods.GetStableHashCode(environment) : 0);
			return Random.CreateFromIndex(math.hash(new uint2(math.hash(new int4(worldSeed, (int)key, (int)(key >> 32), num)), (uint)use)));
		}
	}
	internal class Eased<T> where T : struct
	{
		private readonly Func<T, T, float, T> _lerp;

		private readonly Func<T, T, float> _difference;

		private readonly float _seconds;

		private readonly float _threshold;

		private T _built;

		private bool _started;

		public T Current { get; private set; }

		public int Rebuilds { get; private set; }

		protected Eased(Func<T, T, float, T> lerp, Func<T, T, float> difference, float seconds, float threshold)
		{
			_lerp = lerp;
			_difference = difference;
			_seconds = seconds;
			_threshold = threshold;
		}

		public bool Step(in T target, float dt)
		{
			if (!_started)
			{
				_started = true;
				Current = target;
				return Rebuild();
			}
			if (dt <= 0f)
			{
				return false;
			}
			Current = _lerp(Current, target, 1f - (float)Math.Exp((0f - dt) / _seconds));
			if (_difference(Current, _built) > _threshold)
			{
				return Rebuild();
			}
			return false;
		}

		public void Reset()
		{
			_started = false;
		}

		private bool Rebuild()
		{
			_built = Current;
			Rebuilds++;
			return true;
		}
	}
	internal sealed class HandlerFailure
	{
		private Exception _failure;

		public Action Guard(Action handler)
		{
			return delegate
			{
				if (_failure != null)
				{
					return;
				}
				try
				{
					handler();
				}
				catch (Exception failure)
				{
					_failure = failure;
				}
			};
		}

		public Action<T> Guard<T>(Action<T> handler)
		{
			return delegate(T arg)
			{
				if (_failure != null)
				{
					return;
				}
				try
				{
					handler(arg);
				}
				catch (Exception failure)
				{
					_failure = failure;
				}
			};
		}

		public void Clear()
		{
			_failure = null;
		}

		public void ThrowIfFailed(string what)
		{
			if (_failure == null)
			{
				return;
			}
			Exception failure = _failure;
			_failure = null;
			throw new InvalidOperationException(what + " threw " + failure.GetType().Name + ": " + failure.Message, failure);
		}
	}
	public enum HardwareTier
	{
		Low,
		Medium,
		High,
		Ultra
	}
	public enum ProfileSetting
	{
		Auto,
		Low,
		Medium,
		High,
		Ultra,
		Custom
	}
	internal static class HardwareTiers
	{
		internal static HardwareTier Detect(int videoMemoryMB, int systemMemoryMB, int threads, bool integrated)
		{
			if (integrated)
			{
				return HardwareTier.Low;
			}
			int num = ((videoMemoryMB >= 11000) ? 3 : ((videoMemoryMB >= 7500) ? 2 : ((videoMemoryMB >= 5500) ? 1 : 0)));
			HardwareTier hardwareTier = ((systemMemoryMB >= 30000) ? HardwareTier.Ultra : ((systemMemoryMB >= 15000) ? HardwareTier.High : ((systemMemoryMB >= 11000) ? HardwareTier.Medium : HardwareTier.Low)));
			HardwareTier hardwareTier2 = ((threads >= 8) ? HardwareTier.Ultra : ((threads >= 6) ? HardwareTier.High : ((threads >= 4) ? HardwareTier.Medium : HardwareTier.Low)));
			HardwareTier hardwareTier3 = (HardwareTier)num;
			if (hardwareTier < hardwareTier3)
			{
				hardwareTier3 = hardwareTier;
			}
			if (hardwareTier2 < hardwareTier3)
			{
				hardwareTier3 = hardwareTier2;
			}
			return hardwareTier3;
		}

		internal static HardwareTier Resolve(ProfileSetting setting, HardwareTier detected)
		{
			if (setting != ProfileSetting.Auto && setting != ProfileSetting.Custom)
			{
				return (HardwareTier)(setting - 1);
			}
			return detected;
		}

		internal static int Pick(int configured, int profile)
		{
			if (configured < 0)
			{
				return profile;
			}
			return configured;
		}
	}
	internal sealed class HeightSnapshot
	{
		public float[] Heights;

		public int N;

		public float Step;

		public float OriginX;

		public float OriginZ;

		public int Version;
	}
	internal static class HeightGridBuilder
	{
		public static void Align(float refX, float refZ, int refWidth, float step, float centerX, float centerZ, float half, out float originX, out float originZ, out int n)
		{
			n = (int)Math.Round(2f * half / step) + 1;
			float num = refX - (float)(refWidth / 2) * step;
			float num2 = refZ - (float)(refWidth / 2) * step;
			originX = num + (float)Math.Round((centerX - half - num) / step) * step;
			originZ = num2 + (float)Math.Round((centerZ - half - num2) / step) * step;
		}

		public static bool Overlaps(float hmX, float hmZ, int width, float step, float originX, float originZ, int n)
		{
			float num = (float)width * step * 0.5f;
			float num2 = (float)(n - 1) * step;
			if (!(hmX + num < originX) && !(hmX - num > originX + num2) && !(hmZ + num < originZ))
			{
				return !(hmZ - num > originZ + num2);
			}
			return false;
		}

		public static void Write(float[] grid, int n, float step, float originX, float originZ, float hmX, float hmY, float hmZ, int width, Func<int, int, float> localHeight)
		{
			for (int i = 0; i <= width; i++)
			{
				int num = (int)Math.Round((hmZ + (float)(i - width / 2) * step - originZ) / step);
				if (num < 0 || num >= n)
				{
					continue;
				}
				for (int j = 0; j <= width; j++)
				{
					int num2 = (int)Math.Round((hmX + (float)(j - width / 2) * step - originX) / step);
					if (num2 >= 0 && num2 < n)
					{
						grid[num * n + num2] = localHeight(j, i) + hmY;
					}
				}
			}
		}
	}
	internal interface ILog
	{
		void Info(string message);

		void Warn(string message);

		void Error(string message);
	}
	internal interface IWeatherModule
	{
		string Name { get; }

		bool ConfigEnabled { get; }

		string[] ShadersRequired { get; }

		OwnershipFlags Owns { get; }

		void Enable();

		void Disable();

		void Tick(in WeatherState state);

		void ApplyProfile(HardwareTier tier);
	}
	public enum ModuleState
	{
		Off,
		Running,
		Failed,
		Unsupported
	}
	public struct ModuleStatus
	{
		public string Name;

		public ModuleState State;

		public string Error;
	}
	internal sealed class ModuleHost
	{
		private readonly IReadOnlyList<IWeatherModule> _modules;

		private readonly Func<string, bool> _shaderSupported;

		private readonly ILog _log;

		private readonly ModuleState[] _state;

		private readonly string[] _error;

		private HardwareTier _tier;

		public OwnershipFlags OwnershipOverride;

		public string FailNext;

		private Predicate<IWeatherModule> _only;

		private ModuleStatus[] _status;

		public bool InWorld { get; private set; }

		public ModuleHost(IReadOnlyList<IWeatherModule> modules, Func<string, bool> shaderSupported, ILog log)
		{
			_modules = modules;
			_shaderSupported = shaderSupported;
			_log = log;
			_state = new ModuleState[modules.Count];
			_error = new string[modules.Count];
		}

		public ModuleStatus[] Status()
		{
			if (_status == null || _status.Length != _modules.Count)
			{
				_status = new ModuleStatus[_modules.Count];
			}
			for (int i = 0; i < _modules.Count; i++)
			{
				_status[i] = new ModuleStatus
				{
					Name = _modules[i].Name,
					State = _state[i],
					Error = _error[i]
				};
			}
			return _status;
		}

		public void EnterWorld(HardwareTier tier, Predicate<IWeatherModule> only = null)
		{
			InWorld = true;
			_tier = tier;
			_only = only;
			for (int i = 0; i < _modules.Count; i++)
			{
				if (_state[i] == ModuleState.Failed)
				{
					_state[i] = ModuleState.Off;
					_error[i] = null;
				}
				if (_state[i] == ModuleState.Off || _state[i] == ModuleState.Unsupported)
				{
					TryStart(i);
				}
			}
			Publish();
		}

		public void LeaveWorld()
		{
			for (int i = 0; i < _modules.Count; i++)
			{
				if (_state[i] == ModuleState.Running)
				{
					Stop(i);
				}
				if (_state[i] == ModuleState.Failed)
				{
					_state[i] = ModuleState.Off;
					_error[i] = null;
				}
			}
			InWorld = false;
			_only = null;
			Ownership.Set(OwnershipFlags.None);
		}

		public void Refresh()
		{
			if (!InWorld)
			{
				return;
			}
			bool flag = false;
			for (int i = 0; i < _modules.Count; i++)
			{
				IWeatherModule weatherModule = _modules[i];
				if (_only != null && !_only(weatherModule))
				{
					continue;
				}
				if (!weatherModule.ConfigEnabled)
				{
					if (_state[i] == ModuleState.Running)
					{
						Stop(i);
						flag = true;
					}
					else if (_state[i] == ModuleState.Failed || _state[i] == ModuleState.Unsupported)
					{
						_state[i] = ModuleState.Off;
						_error[i] = null;
						flag = true;
					}
				}
				else if (_state[i] == ModuleState.Off)
				{
					TryStart(i);
					flag = true;
				}
			}
			if (flag)
			{
				Publish();
			}
		}

		public void ApplyProfile(HardwareTier tier)
		{
			_tier = tier;
			for (int i = 0; i < _modules.Count; i++)
			{
				if (_state[i] == ModuleState.Running)
				{
					try
					{
						_modules[i].ApplyProfile(tier);
					}
					catch (Exception e)
					{
						Fail(i, e);
					}
				}
			}
			Publish();
		}

		public void Tick(in WeatherState state)
		{
			for (int i = 0; i < _modules.Count; i++)
			{
				if (_state[i] != ModuleState.Running)
				{
					continue;
				}
				IWeatherModule weatherModule = _modules[i];
				try
				{
					if (FailNext != null && FailNext == weatherModule.Name)
					{
						FailNext = null;
						throw new InvalidOperationException("failure injected by diagnostics");
					}
					weatherModule.Tick(in state);
				}
				catch (Exception e)
				{
					Fail(i, e);
				}
			}
			Publish();
		}

		private void TryStart(int i)
		{
			IWeatherModule weatherModule = _modules[i];
			if (!weatherModule.ConfigEnabled || (_only != null && !_only(weatherModule)))
			{
				_state[i] = ModuleState.Off;
				return;
			}
			string[] shadersRequired = weatherModule.ShadersRequired;
			foreach (string text in shadersRequired)
			{
				if (!_shaderSupported(text))
				{
					if (_state[i] != ModuleState.Unsupported)
					{
						_log.Warn("[core] " + weatherModule.Name + " needs shader " + text + ", which is missing or unsupported on this machine; the module stays off.");
					}
					_state[i] = ModuleState.Unsupported;
					return;
				}
			}
			try
			{
				weatherModule.Enable();
				weatherModule.ApplyProfile(_tier);
				_state[i] = ModuleState.Running;
				_error[i] = null;
				_log.Info($"[core] {weatherModule.Name} on ({_tier})");
			}
			catch (Exception e)
			{
				Fail(i, e);
			}
		}

		private void Stop(int i)
		{
			IWeatherModule weatherModule = _modules[i];
			try
			{
				weatherModule.Disable();
			}
			catch (Exception ex)
			{
				_log.Error("[core] " + weatherModule.Name + " failed while shutting down: " + ex.GetType().Name + ": " + ex.Message);
			}
			_state[i] = ModuleState.Off;
		}

		private void Fail(int i, Exception e)
		{
			IWeatherModule weatherModule = _modules[i];
			_error[i] = e.GetType().Name + ": " + e.Message;
			_state[i] = ModuleState.Failed;
			_log.Error("[core] " + weatherModule.Name + " failed and is off until it is turned off and on again or a new world is entered: " + _error[i]);
			try
			{
				weatherModule.Disable();
			}
			catch (Exception ex)
			{
				_log.Warn("[core] " + weatherModule.Name + " also failed while shutting down: " + ex.GetType().Name + ": " + ex.Message);
			}
		}

		private void Publish()
		{
			OwnershipFlags ownershipFlags = OwnershipOverride;
			for (int i = 0; i < _modules.Count; i++)
			{
				if (_state[i] == ModuleState.Running)
				{
					ownershipFlags |= _modules[i].Owns;
				}
			}
			Ownership.Set(InWorld ? ownershipFlags : OwnershipFlags.None);
		}
	}
	internal static class MoonCycle
	{
		public const double CycleDays = 30.0;

		public static readonly string[] PhaseNames = new string[8] { "new", "waxing_crescent", "first_quarter", "waxing_gibbous", "full", "waning_gibbous", "last_quarter", "waning_crescent" };

		public static float Age(double days)
		{
			double num = days / 30.0 + 0.5;
			return (float)(num - Math.Floor(num));
		}

		public static int NightPhase(double days)
		{
			return (int)Math.Floor((double)Age((double)Night(days) + 1.0) * 8.0 + 0.5) % 8;
		}

		public static long Night(double days)
		{
			return (long)Math.Floor(days - 0.5);
		}

		public static double DaysFromNoon(double days)
		{
			double num = days - 0.5 - Math.Floor(days - 0.5);
			return Math.Min(num, 1.0 - num);
		}
	}
	internal static class NightAmbient
	{
		public static float Lift(float ambient, float daytime, float nightWeight, float boost)
		{
			float num = Math.Max(0f, Math.Min(1f, nightWeight)) * Math.Max(0f, Math.Min(1f, boost));
			return ambient + Math.Max(0f, daytime - ambient) * num;
		}
	}
	internal struct NightPlace
	{
		private bool _seen;

		private bool _interior;

		public bool Outdoors(bool hasPlayer, bool interior)
		{
			if (hasPlayer)
			{
				_seen = true;
				_interior = interior;
			}
			if (_seen)
			{
				return !_interior;
			}
			return false;
		}

		public void Reset()
		{
			_seen = false;
			_interior = false;
		}
	}
	[Flags]
	public enum OwnershipFlags
	{
		None = 0,
		Sky = 1,
		Clouds = 2,
		Fog = 4,
		ColorGrading = 8,
		WaterSurface = 0x10,
		WetSurfaces = 0x20,
		Snow = 0x40,
		ReflectionProbes = 0x80,
		Precipitation = 0x100
	}
	public static class Ownership
	{
		public static OwnershipFlags Current { get; private set; }

		public static event Action Changed;

		internal static event Action<Delegate, Exception> HandlerFailed;

		public static bool Owns(OwnershipFlags flags)
		{
			if (flags != OwnershipFlags.None)
			{
				return (Current & flags) == flags;
			}
			return false;
		}

		internal static void Set(OwnershipFlags flags)
		{
			if (flags != Current)
			{
				Current = flags;
				SafeEvents.Raise(Ownership.Changed, Ownership.HandlerFailed);
			}
		}
	}
	internal enum RescanDecision
	{
		None,
		Rescan,
		RescanAndHide
	}
	internal sealed class RescanPolicy
	{
		public const float TeleportDistance = 200f;

		public const float TerrainSettleSeconds = 0.75f;

		public float WindowHalf = 64f;

		private bool _hasCenter;

		private float _cx;

		private float _cz;

		private int _configVersion;

		private bool _dirty;

		private float _lastChange;

		public RescanDecision Decide(float px, float pz, int configVersion, bool scanRunning, float now)
		{
			if (scanRunning)
			{
				return RescanDecision.None;
			}
			if (!_hasCenter)
			{
				return RescanDecision.RescanAndHide;
			}
			float num = px - _cx;
			float num2 = pz - _cz;
			float num3 = (float)Math.Sqrt(num * num + num2 * num2);
			if (num3 >= 200f)
			{
				return RescanDecision.RescanAndHide;
			}
			bool flag = _dirty && now - _lastChange >= 0.75f;
			if (num3 >= WindowHalf * 0.5f || configVersion != _configVersion || flag)
			{
				return RescanDecision.Rescan;
			}
			return RescanDecision.None;
		}

		public void Started(float px, float pz, int configVersion)
		{
			_hasCenter = true;
			_cx = px;
			_cz = pz;
			_configVersion = configVersion;
			_dirty = false;
		}

		public void MarkTerrainChanged(float minX, float maxX, float minZ, float maxZ, float now)
		{
			if (_hasCenter && maxX >= _cx - WindowHalf && minX <= _cx + WindowHalf && maxZ >= _cz - WindowHalf && minZ <= _cz + WindowHalf)
			{
				_dirty = true;
				_lastChange = now;
			}
		}

		public void Reset()
		{
			_hasCenter = false;
			_dirty = false;
		}
	}
	internal static class SafeEvents
	{
		public static void Raise<T>(Action<T> handlers, T arg, Action<Delegate, Exception> failed, HandlerList list = null)
		{
			if (handlers == null)
			{
				return;
			}
			Delegate[] array = ((list != null) ? list.Of(handlers) : handlers.GetInvocationList());
			foreach (Delegate obj in array)
			{
				try
				{
					((Action<T>)obj)(arg);
				}
				catch (Exception arg2)
				{
					failed?.Invoke(obj, arg2);
				}
			}
		}

		public static void Raise(Action handlers, Action<Delegate, Exception> failed, HandlerList list = null)
		{
			if (handlers == null)
			{
				return;
			}
			Delegate[] array = ((list != null) ? list.Of(handlers) : handlers.GetInvocationList());
			foreach (Delegate obj in array)
			{
				try
				{
					((Action)obj)();
				}
				catch (Exception arg)
				{
					failed?.Invoke(obj, arg);
				}
			}
		}
	}
	internal sealed class HandlerList
	{
		private Delegate _of;

		private Delegate[] _list = Array.Empty<Delegate>();

		public Delegate[] Of(Delegate handlers)
		{
			if ((object)handlers != _of)
			{
				_of = handlers;
				_list = handlers.GetInvocationList();
			}
			return _list;
		}
	}
	public static class Weather
	{
		public static WeatherState Current { get; internal set; }
	}
	public struct EnvDescriptor
	{
		public string Name;

		public bool IsWet;

		public bool IsFreezing;

		public float SnowBuildup;

		public bool HasParticles;

		public bool HasSnowParticles;

		public bool HasLightning;

		public float FogDensity;

		public float WindMin;

		public float WindMax;
	}
	public struct WeatherState
	{
		public bool InWorld;

		public bool HasPlayer;

		public bool MainMenu;

		public string Environment;

		public bool Forced;

		public bool CameraUnderWater;

		public float Transition;

		public float Rain;

		public float Wetness;

		public float SnowFall;

		public float Snowiness;

		public float Fog;

		public float Lightning;

		public float SnowBuildup;

		public float WindX;

		public float WindZ;

		public float WindStrength;

		public int WorldSeed;

		public int Day;

		public double WorldSeconds;

		public long Period;

		public float DayFraction;

		public float SunDirX;

		public float SunDirY;

		public float SunDirZ;

		public float SunR;

		public float SunG;

		public float SunB;

		public float SkySunDirX;

		public float SkySunDirY;

		public float SkySunDirZ;

		public int Biome;

		public float PlayerX;

		public float PlayerY;

		public float PlayerZ;

		public DayVariation Variation;

		public float TargetRain;

		public float TargetSnowFall;

		public float TargetFog;

		public float TargetLightning;

		public float TargetSnowBuildup;

		public WeatherTune Tune;

		public bool GameLightIsMoon => SunDirX * SkySunDirX + SunDirY * SkySunDirY + SunDirZ * SkySunDirZ < 0f;
	}
	internal static class WeatherBlend
	{
		public static float RainOf(in EnvDescriptor e)
		{
			if (!e.IsWet || SnowOf(in e) != 0f)
			{
				return 0f;
			}
			return 1f;
		}

		public static float SnowOf(in EnvDescriptor e)
		{
			if (!(e.SnowBuildup > 0f) && (!e.HasParticles || (!e.IsFreezing && !e.HasSnowParticles)))
			{
				return 0f;
			}
			return 1f;
		}

		public static float FreezingOf(in EnvDescriptor e)
		{
			if (!e.IsFreezing)
			{
				return 0f;
			}
			return 1f;
		}

		public static float LightningOf(in EnvDescriptor e)
		{
			if (!e.HasLightning)
			{
				return 0f;
			}
			return 1f;
		}

		public static bool IsBlending(bool forced, bool hasPrev, bool hasNext)
		{
			return !forced && hasPrev && hasNext;
		}

		public static float Blend(float from, float to, float t)
		{
			return from + (to - from) * Math.Min(1f, Math.Max(0f, t));
		}
	}
	public struct WeatherTune
	{
		public float CloudCover;

		private float _cloudBrightness;

		private float _skyBrightness;

		private float _visibility;

		private float _light;

		private float _tintR;

		private float _tintG;

		private float _tintB;

		public float CloudBrightness
		{
			get
			{
				return 1f + _cloudBrightness;
			}
			set
			{
				_cloudBrightness = value - 1f;
			}
		}

		public float SkyBrightness
		{
			get
			{
				return 1f + _skyBrightness;
			}
			set
			{
				_skyBrightness = value - 1f;
			}
		}

		public float Visibility
		{
			get
			{
				return 1f + _visibility;
			}
			set
			{
				_visibility = value - 1f;
			}
		}

		public float Light
		{
			get
			{
				return 1f + _light;
			}
			set
			{
				_light = value - 1f;
			}
		}

		public float TintR
		{
			get
			{
				return 1f + _tintR;
			}
			set
			{
				_tintR = value - 1f;
			}
		}

		public float TintG
		{
			get
			{
				return 1f + _tintG;
			}
			set
			{
				_tintG = value - 1f;
			}
		}

		public float TintB
		{
			get
			{
				return 1f + _tintB;
			}
			set
			{
				_tintB = value - 1f;
			}
		}

		public bool IsNeutral => Same(default(WeatherTune));

		public bool LightNeutral
		{
			get
			{
				if (_light == 0f && _tintR == 0f && _tintG == 0f)
				{
					return _tintB == 0f;
				}
				return false;
			}
		}

		public bool Same(in WeatherTune o)
		{
			if (CloudCover == o.CloudCover && _cloudBrightness == o._cloudBrightness && _skyBrightness == o._skyBrightness && _visibility == o._visibility && _light == o._light && _tintR == o._tintR && _tintG == o._tintG)
			{
				return _tintB == o._tintB;
			}
			return false;
		}

		public static WeatherTune Of(float cloudCover, float cloudBrightness, float skyBrightness, float visibility, float light = 1f, float tintR = 1f, float tintG = 1f, float tintB = 1f)
		{
			return new WeatherTune
			{
				CloudCover = (float.IsNaN(cloudCover) ? 0f : Math.Min(1f, Math.Max(-1f, cloudCover))),
				CloudBrightness = Factor(cloudBrightness),
				SkyBrightness = Factor(skyBrightness),
				Visibility = Factor(visibility),
				Light = Factor(light),
				TintR = Factor(tintR),
				TintG = Factor(tintG),
				TintB = Factor(tintB)
			};
		}

		public static WeatherTune Combine(in WeatherTune a, in WeatherTune b)
		{
			return Of(a.CloudCover + b.CloudCover, a.CloudBrightness * b.CloudBrightness, a.SkyBrightness * b.SkyBrightness, a.Visibility * b.Visibility, a.Light * b.Light, a.TintR * b.TintR, a.TintG * b.TintG, a.TintB * b.TintB);
		}

		public static WeatherTune Lerp(in WeatherTune a, in WeatherTune b, float t)
		{
			t = (float.IsNaN(t) ? 1f : Math.Min(1f, Math.Max(0f, t)));
			return Of(L(a.CloudCover, b.CloudCover, t), L(a.CloudBrightness, b.CloudBrightness, t), L(a.SkyBrightness, b.SkyBrightness, t), L(a.Visibility, b.Visibility, t), L(a.Light, b.Light, t), L(a.TintR, b.TintR, t), L(a.TintG, b.TintG, t), L(a.TintB, b.TintB, t));
		}

		private static float Factor(float v)
		{
			if (!float.IsNaN(v) && !float.IsInfinity(v))
			{
				return Math.Max(0f, v);
			}
			return 1f;
		}

		private static float L(float a, float b, float t)
		{
			return a + (b - a) * t;
		}
	}
	internal struct WorldEvent
	{
		public double Time;

		public float X;

		public float Z;

		public uint Key;

		public Random Draws()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return Random.CreateFromIndex(Key);
		}
	}
	internal sealed class WorldEventStream
	{
		private const int MaxPerCell = 64;

		private readonly uint _use;

		private readonly double _limit;

		public readonly float Cell;

		public readonly double Slot;

		public readonly double Density;

		public WorldEventStream(DayVariations.Use use, float cell, double slot, double density)
		{
			_use = (uint)use;
			Cell = cell;
			Slot = slot;
			Density = density;
			_limit = Math.Exp((0.0 - density) * (double)cell * (double)cell * slot);
		}

		public void CellEvents(int worldSeed, int ix, int iz, long k, List<WorldEvent> into)
		{
			//IL_0009: 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_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)
			Random r = Random.CreateFromIndex(math.hash(new uint3(math.hash(new int4(worldSeed, ix, iz, (int)_use)), (uint)k, (uint)(k >> 32))));
			int num = Poisson(ref r, _limit);
			for (int i = 0; i < num; i++)
			{
				into.Add(new WorldEvent
				{
					Time = ((double)k + ((Random)(ref r)).NextDouble()) * Slot,
					X = ((float)ix + ((Random)(ref r)).NextFloat()) * Cell,
					Z = ((float)iz + ((Random)(ref r)).NextFloat()) * Cell,
					Key = ((Random)(ref r)).NextUInt()
				});
			}
		}

		public void Collect(int worldSeed, double from, double to, float x, float z, float radius, List<WorldEvent> into)
		{
			if (!(to > from) || !(radius > 0f) || float.IsNaN(x) || float.IsNaN(z) || float.IsInfinity(x) || float.IsInfinity(z))
			{
				return;
			}
			int num = (int)Math.Floor((x - radius) / Cell);
			int num2 = (int)Math.Floor((x + radius) / Cell);
			int num3 = (int)Math.Floor((z - radius) / Cell);
			int num4 = (int)Math.Floor((z + radius) / Cell);
			for (int i = num; i <= num2; i++)
			{
				for (int j = num3; j <= num4; j++)
				{
					CollectCell(worldSeed, i, j, from, to, x, z, radius, into);
				}
			}
		}

		public void CollectCell(int worldSeed, int ix, int iz, double from, double to, float x, float z, float radius, List<WorldEvent> into)
		{
			float num = Math.Max((float)ix * Cell, Math.Min(x, (float)(ix + 1) * Cell)) - x;
			float num2 = Math.Max((float)iz * Cell, Math.Min(z, (float)(iz + 1) * Cell)) - z;
			if (num * num + num2 * num2 > radius * radius)
			{
				return;
			}
			long num3 = (long)Math.Floor(from / Slot);
			long num4 = (long)Math.Floor(to / Slot);
			for (long num5 = num3; num5 <= num4; num5++)
			{
				int count = into.Count;
				CellEvents(worldSeed, ix, iz, num5, into);
				int num6 = count;
				for (int i = count; i < into.Count; i++)
				{
					WorldEvent value = into[i];
					float num7 = value.X - x;
					float num8 = value.Z - z;
					if (value.Time > from && value.Time <= to && num7 * num7 + num8 * num8 <= radius * radius)
					{
						into[num6++] = value;
					}
				}
				into.RemoveRange(num6, into.Count - num6);
			}
		}

		private static int Poisson(ref Random r, double limit)
		{
			if (!(limit < 1.0))
			{
				return 0;
			}
			double num = ((Random)(ref r)).NextDouble();
			int num2 = 0;
			while (num > limit && num2 < 64)
			{
				num2++;
				num *= ((Random)(ref r)).NextDouble();
			}
			return num2;
		}
	}
	internal struct WorldTimeWindow
	{
		public const double MaxCatchUp = 2.0;

		private double _to;

		private bool _started;

		public bool Advance(double now, out double from, out double to)
		{
			from = (to = now);
			if (double.IsNaN(now) || double.IsInfinity(now))
			{
				return false;
			}
			if (!_started || now - _to > 2.0 || _to - now > 60.0)
			{
				_started = true;
				_to = now;
				return false;
			}
			if (!(now > _to))
			{
				return false;
			}
			from = _to;
			_to = now;
			return true;
		}

		public void Reset()
		{
			_started = false;
		}
	}
	internal enum Presence
	{
		Playing,
		Waiting,
		Gone
	}
	internal static class WorldPresence
	{
		public static Presence Of(bool inWorld, bool hasPlayer)
		{
			if (inWorld)
			{
				if (!hasPlayer)
				{
					return Presence.Waiting;
				}
				return Presence.Playing;
			}
			return Presence.Gone;
		}
	}
	internal sealed class AirConfig
	{
		private const string S = "Air";

		public readonly ConfigEntry<bool> Enabled;

		public readonly ConfigEntry<AirStyle> Style;

		public readonly ConfigEntry<Haze> HazeLevel;

		public readonly ConfigEntry<float> VisibilityScale;

		public readonly ConfigEntry<bool> VolumetricLight;

		public readonly ConfigEntry<float> ShaftStrength;

		public readonly ConfigEntry<float> NearHaze;

		public readonly ConfigEntry<float> NearHazeDistance;

		public readonly ConfigEntry<float> FarLandsHaze;

		public readonly ConfigEntry<float> MistLimit;

		public readonly ConfigEntry<bool> SeaMist;

		public readonly ConfigEntry<bool> SeaMistOnlyAtSea;

		public readonly ConfigEntry<bool> HazeInReflections;

		public readonly ConfigEntry<float> SeaMistVisibility;

		public readonly ConfigEntry<float> SeaMistHeight;

		public readonly ConfigEntry<float> FogDistance;

		public readonly ConfigEntry<int> FogSlices;

		private bool _applying;

		public AirConfig(ConfigFile cfg)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Expected O, but got Unknown
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Expected O, but got Unknown
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Expected O, but got Unknown
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Expected O, but got Unknown
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Expected O, but got Unknown
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Expected O, but got Unknown
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Expected O, but got Unknown
			Enabled = cfg.BindListed("Air", "Enabled", value: true, "Clearer air instead of the game's fog: the game's own fog colours for every biome, weather and time of day, seen 5 to 8 times further (about 6 km on a clear day, 1 km in rain); haze and fog thin out with height, mist lies in the lowlands at dawn, and the distant land and the sky's horizon dissolve into the same haze.");
			Style = cfg.BindListed("Air", "AirStyle", AirStyle.North, "The sky's atmosphere. North: clean northern air with more ozone (deeper blue at dusk). Earth: the average atmosphere.");
			bool inFile = HasSaved(cfg, "Air", "Haze");
			HazeLevel = cfg.BindListed("Air", "Haze", Haze.Standard, "How hazy the air is: Clear, Light, Standard or Thick sets NearHaze, NearHazeDistance and FarLandsHaze together (Light and Clear: the near haze reaches farther, the far land is clearer; Thick: more of both). Changing one of them by hand makes it Custom.");
			VisibilityScale = cfg.BindListed("Air", "VisibilityScale", 1f, new ConfigDescription("Multiplies how far one sees in every weather (below 1 thicker air, above 1 clearer).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			NearHaze = cfg.BindListed("Air", "NearHaze", 0.6f, new ConfigDescription("How much of the game's own haze stays on things near you (1: the game's density close by, as on its trees; less keeps more contrast), fading out by NearHazeDistance so far views stay clear. 0: the clear air alone.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			NearHazeDistance = cfg.BindListed("Air", "NearHazeDistance", 50f, new ConfigDescription("Over how many metres the near haze fades out.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(50f, 1000f), Array.Empty<object>()));
			FarLandsHaze = cfg.BindListed("Air", "FarLandsHaze", 1f, new ConfigDescription("How much haze stays over FarLands' far land in clear weather: 1 all, 0 none. Rain, snow and fog keep all of theirs. Only with FarLands; this, not FarLands' own setting, is used while this air is on.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			MistLimit = cfg.BindListed("Air", "MistLimit", 0.8f, new ConfigDescription("How much the morning mist may hide of the land however far off (the mist's optical depth along a view, softly limited). 0.8: at least about 45% of the far land's own look shows through, so its relief stays; higher thickens the distant mist towards a flat grey wall (2: about 14%). 0: no limit.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			SeaMist = cfg.BindListed("Air", "SeaMist", value: true, "A mist over the sea: out on the water the shores a kilometre or two off sink into it while nearer ones stand out, so the sea keeps its distance (without it, with FarLands, every shore is seen for kilometres). Fades out in rain and snow, whose own haze takes over.");
			SeaMistOnlyAtSea = cfg.BindListed("Air", "SeaMistOnlyAtSea", value: true, "The sea mist only while you are out at sea (the Ocean biome; not over lakes; it eases in and out over a few seconds); off: everywhere, on land too.");
			SeaMistVisibility = cfg.BindListed("Air", "SeaMistVisibility", 1500f, new ConfigDescription("How far one sees through the sea mist at the water's level, metres: less is thicker.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(500f, 20000f), Array.Empty<object>()));
			SeaMistHeight = cfg.BindListed("Air", "SeaMistHeight", 150f, new ConfigDescription("Over how many metres above the sea the sea mist thins out (to about a third): low keeps the hills above it, high hides them too.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 200f), Array.Empty<object>()));
			HazeInReflections = cfg.BindListed("Air", "HazeInReflections", value: true, "The water mirrors the far shores through the same haze you see them through. Off: the reflections stay clear, as without the air (sharper, though a mirrored shore then stands out of the haze over it).");
			VolumetricLight = cfg.BindListed("Air", "VolumetricLight", value: true, "Light shafts in the air: the haze and fog around the view are lit by the sun or the moon with the game's shadows and the clouds' (trees, mountains and gaps in the clouds cast beams, strongest in mist and haze), with the game's own sun shafts, which now take their light from the sun and the clear sky only (the clouds no longer grey the sky through them). Off on the Low profile. Needs compute shaders.");
			ShaftStrength = cfg.BindListed("Air", "ShaftStrength", 1f, new ConfigDescription("How deep the shadows of trees, mountains and clouds are in the air. 1: as the haze makes them (in clear air the shafts are faint, as in life); higher darkens the shadowed air more, so the shafts stand out, without making the lit air or the sky brighter, but the forest around darkens with it. 0: no shafts in the air (the game's sun shafts stay). 1 is the faintest the shafts go: values between 0 and 1 act as 1.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>()));
			FogDistance = cfg.BindListed("Air", "FogDistance", -1f, new ConfigDescription("How far the shafts reach, metres; -1 follows the profile (Medium 128, High 256, Ultra 512).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1024f), Array.Empty<object>()));
			FogSlices = cfg.BindListed("Air", "FogSlices", -1, new ConfigDescription("Depth slices of the shaft grid; -1 follows the profile (Medium 48, High 64, Ultra 96).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1, 128), Array.Empty<object>()));
			HazeLevel.Value = HazePresets.OnLoad(HazeLevel.Value, inFile, CurrentHaze(), out var apply);
			if (apply)
			{
				ApplyHaze(HazePresets.Get(HazeLevel.Value));
			}
			HazeLevel.SettingChanged += delegate
			{
				if (!_applying && HazeLevel.Value != Haze.Custom)
				{
					ApplyHaze(HazePresets.Get(HazeLevel.Value));
				}
			};
			ConfigEntryBase[] hazeSettings = (ConfigEntryBase[])(object)new ConfigEntryBase[3]
			{
				(ConfigEntryBase)NearHaze,
				(ConfigEntryBase)NearHazeDistance,
				(ConfigEntryBase)FarLandsHaze
			};
			cfg.SettingChanged += delegate(object s, SettingChangedEventArgs e)
			{
				if (!_applying && Array.IndexOf(hazeSettings, e.ChangedSetting) >= 0)
				{
					SyncHaze();
				}
			};
		}

		private HazeValues CurrentHaze()
		{
			return new HazeValues(NearHaze.Value, NearHazeDistance.Value, FarLandsHaze.Value);
		}

		private void ApplyHaze(HazeValues h)
		{
			_applying = true;
			try
			{
				NearHaze.Value = h.NearHaze;
				NearHazeDistance.Value = h.NearHazeDistance;
				FarLandsHaze.Value = h.FarLandsHaze;
			}
			finally
			{
				_applying = false;
			}
		}

		private void SyncHaze()
		{
			_applying = true;
			try
			{
				HazeLevel.Value = HazePresets.Match(CurrentHaze());
			}
			finally
			{
				_applying = false;
			}
		}

		private static bool HasSaved(ConfigFile cfg, string section, string key)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			return ConfigLayout.Saved(cfg).ContainsKey(new ConfigDefinition(section, key));
		}
	}
	internal sealed class AirEase
	{
		public const float Seconds = 8f;

		private bool _have;

		public float View { get; private set; }

		public float Height { get; private set; }

		public float Mist { get; private set; }

		public float Sea { get; private set; }

		public void Step(float view, float height, float mist, float dt, float sea = 0f)
		{
			if (!float.IsNaN(view) && !float.IsNaN(height) && !float.IsNaN(mist) && !float.IsNaN(sea) && view > 0f)
			{
				if (!_have)
				{
					View = view;
					Height = height;
					Mist = mist;
					Sea = sea;
					_have = true;
				}
				else if (dt >= 0f)
				{
					float num = 1f - (float)Math.Exp((0f - Math.Min(dt, 10000f)) / 8f);
					View = (float)Math.Exp(Math.Log(View) + (Math.Log(view) - Math.Log(View)) * (double)num);
					Height += (height - Height) * num;
					Mist += (mist - Mist) * num;
					Sea += (sea - Sea) * num;
				}
			}
		}

		public void Reset()
		{
			_have = false;
		}
	}
	internal sealed class AirFog
	{
		private static readonly int Ray00Id = Shader.PropertyToID("_WO_AirRay00");

		private static readonly int Ray10Id = Shader.PropertyToID("_WO_AirRay10");

		private static readonly int Ray01Id = Shader.PropertyToID("_WO_AirRay01");

		private static readonly int Ray11Id = Shader.PropertyToID("_WO_AirRay11");

		private static readonly int CameraId = Shader.PropertyToID("_WO_AirCamera");

		private static readonly int ForwardId = Shader.PropertyToID("_WO_AirCamForward");

		private static readonly int LayersId = Shader.PropertyToID("_WO_AirLayers");

		private static readonly int FadeId = Shader.PropertyToID("_WO_AirFade");

		private static readonly int FogColorId = Shader.PropertyToID("_WO_AirFogColor");

		private static readonly int SunFogColorId = Shader.PropertyToID("_WO_AirSunFogColor");

		private static readonly int SunId = Shader.PropertyToID("_WO_AirSun");

		private static readonly int FarId = Shader.PropertyToID("_WO_AirFar");

		private static readonly int SeaId = Shader.PropertyToID("_WO_AirSea");

		private static readonly int VolId = Shader.PropertyToID("_WO_AirVol");

		private static readonly int VolEncodeId = Shader.PropertyToID("_WO_AirVolEncode");

		private static readonly int NearId = Shader.PropertyToID("_WO_AirNear");

		private static readonly int VolDecodeId = Shader.PropertyToID("_WO_AirVolDecode");

		private static readonly int TerrainId = Shader.PropertyToID("_WO_AirTerrain");

		private static readonly int WaterAfterId = Shader.PropertyToID("_WO_AirWaterAfter");

		private static readonly int GameSkyId = Shader.PropertyToID("_WO_AirGameSky");

		private readonly FramePipeline _pipeline;

		private readonly Material _material;

		private readonly CommandBuffer _cb;

		private readonly Material _waterMaterial;

		private const int WaterQueue = 2901;

		private readonly Material _probeMaterial;

		private readonly CommandBuffer _probeCb;

		private Vector4 _near;

		private bool _shown;

		private bool _reflections;

		private bool _probeDirty = true;

		private bool _waterDirty = true;

		private RenderTexture _shafts;

		private static readonly int TreeAirId = Shader.PropertyToID("_WO_TreeAir");

		private static readonly int GlowId = Shader.PropertyToID("_WO_AirGlow");

		private static readonly int ShaftsId = Shader.PropertyToID("_WO_AirShafts");

		private static readonly int ShaftsSizeId = Shader.PropertyToID("_WO_AirShaftsSize");

		private float _water;

		public AirFog(Shader shader, Shader waterShader, FramePipeline pipeline)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_0076: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			//IL_00cf: 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_00e1: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Expected O, but got Unknown
			_pipeline = pipeline;
			_material = new Material(shader)
			{
				hideFlags = (HideFlags)61
			};
			_material.SetFloat(TreeAirId, 1f);
			_material.SetFloat(GlowId, 1f);
			_cb = new CommandBuffer
			{
				name = "WeatherOverhaul air"
			};
			_cb.SetRenderTarget(RenderTargetIdentifier.op_Implicit((BuiltinRenderTextureType)2));
			_cb.DrawProcedural(Matrix4x4.identity, _material, 0, (MeshTopology)0, 3);
			_material.SetFloat(WaterAfterId, 1f);
			_waterMaterial = new Material(waterShader)
			{
				name = "WeatherOverhaul air (water)",
				hideFlags = (HideFlags)61
			};
			_probeMaterial = new Material(shader)
			{
				hideFlags = (HideFlags)61
			};
			_probeCb = new CommandBuffer
			{
				name = "WeatherOverhaul air (reflections)"
			};
			_probeCb.SetRenderTarget(RenderTargetIdentifier.op_Implicit((BuiltinRenderTextureType)2));
			_probeCb.DrawProcedural(Matrix4x4.identity, _probeMaterial, 0, (MeshTopology)0, 3);
			Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnPreCull));
		}

		public void Set(float water, in AirLayer haze, in AirLayer mist, in AirLayer sea, float mistCap, float terrainX, float terrainZ, float terrainHalf, float safeEdge, float lodHide, bool skyDrawn, Color fogLinear, Color sunFogLinear, Vector3 sunDir, bool farLands, float farKnee, float farRate, float gameLight, float gameSky, float gameSkyMin, float gameSkyMax)
		{
			//IL_004e: 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_00b9: 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_0107: 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_0123: 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_0138: 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_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: 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_017c: 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_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: 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)
			_material.SetVector(FarId, new Vector4(Mathf.Max(0f, farKnee), farLands ? Mathf.Clamp01(1f - farRate) : 0f, Mathf.Max(0f, mistCap), WeatherDiagnostics.AirMistLog ? 1f : 0f));
			_water = water;
			_material.SetVector(LayersId, new Vector4(haze.Density, haze.Height, mist.Density, mist.Height));
			_material.SetVector(SeaId, new Vector4(sea.Density, Mathf.Max(sea.Height, 1f), 0f, 0f));
			_material.SetVector(FadeId, new Vector4(0.75f, 0.97f, skyDrawn ? 1f : 0f, lodHide));
			_material.SetVector(TerrainId, new Vector4(terrainX, terrainZ, terrainHalf, safeEdge));
			_material.SetVector(FogColorId, new Vector4(fogLinear.r, fogLinear.g, fogLinear.b, Mathf.Clamp01(gameLight)));
			_material.SetVector(SunFogColorId, new Vector4(sunFogLinear.r, sunFogLinear.g, sunFogLinear.b, 0f));
			_material.SetVector(SunId, new Vector4(sunDir.x, sunDir.y, sunDir.z, farLands ? 0f : 1f));
			_material.SetVector(GameSkyId, new Vector4(Mathf.Clamp01(gameSky), gameSkyMin, gameSkyMax, 0f));
			_probeDirty = (_waterDirty = true);
		}

		private void SyncProbe()
		{
			//IL_001c: 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)
			_probeMaterial.CopyPropertiesFromMaterial(_material);
			_probeMaterial.SetVector(VolId, Vector4.zero);
			_probeMaterial.SetFloat(TreeAirId, 0f);
			_probeMaterial.SetFloat(GlowId, 0f);
			_probeMaterial.SetFloat(WaterAfterId, 0f);
			_probeMaterial.SetVector(NearId, new Vector4(_near.x, _near.y, 0f, _near.w));
		}

		public void SetVolume(RenderTexture lighting, Vector4 encode, Vector4 decode, float range, int slices, bool on)
		{
			//IL_000b: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			_material.SetVector(VolDecodeId, decode);
			bool flag = on && (Object)(object)lighting != (Object)null && slices > 0;
			_material.SetVector(VolId, new Vector4(flag ? 1f : 0f, (float)slices, range, (slices > 0) ? (1f / (float)slices) : 0f));
			_material.SetVector(VolEncodeId, encode);
			_probeDirty = (_waterDirty = true);
		}

		public void SetNear(float density, float reach)
		{
			//IL_0048: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			_near = new Vector4(density, Mathf.Max(reach, 1f), (!((Object)(object)_shafts != (Object)null)) ? 0f : (WeatherDiagnostics.AirShaftsView ? 2f : 1f), WeatherDiagnostics.AirBelowHorizonAsSky ? 1f : 0f);
			_material.SetVector(NearId, _near);
			_probeDirty = (_waterDirty = true);
		}

		public void SetShafts(RenderTexture shafts)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			bool num = (Object)(object)_shafts != (Object)null;
			_shafts = shafts;
			if ((Object)(object)shafts != (Object)null)
			{
				_material.SetTexture(ShaftsId, (Texture)(object)shafts);
				_material.SetVector(ShaftsSizeId, new Vector4((float)((Texture)shafts).width, (float)((Texture)shafts).height, 1f / (float)((Texture)shafts).width, 1f / (float)((Texture)shafts).height));
			}
			else
			{
				_material.SetTexture(ShaftsId, (Texture)null);
			}
			_waterDirty = true;
			if (num != ((Object)(object)shafts != (Object)null))
			{
				SetNear(_near.x, _near.y);
			}
		}

		public void SetVolume(VolumetricBuffer volume)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			SetShafts(volume.Shafts);
			SetVolume(volume.Lighting, volume.EncodeParams, volume.DecodeParams, volume.Range, volume.Slices, on: true);
		}

		public void Show(bool on, bool reflections = false)
		{
			reflections = reflections && on;
			if (on != _shown)
			{
				if (on)
				{
					_pipeline.Add((CameraEvent)13, _cb);
				}
				else
				{
					_pipeline.Remove(_cb);
				}
				_shown = on;
			}
			if (reflections != _reflections)
			{
				if (reflections)
				{
					_pipeline.AddToReflectionCameras((CameraEvent)16, _probeCb);
				}
				else
				{
					_pipeline.Remove(_probeCb);
				}
				_reflections = reflections;
			}
		}

		public void Destroy()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			Show(on: false);
			Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnPreCull));
			_cb.Release();
			_probeCb.Release();
			Object.Destroy((Object)(object)_material);
			Object.Destroy((Object)(object)_waterMaterial);
			Object.Destroy((Object)(object)_probeMaterial);
		}

		private void OnPreCull(Camera cam)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Invalid comparison between Unknown and I4
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if (!_shown || (Object)(object)cam == (Object)null)
			{
				return;
			}
			if ((Object)(object)cam == (Object)(object)_pipeline.Camera)
			{
				if (_waterDirty)
				{
					_waterMaterial.CopyPropertiesFromMaterial(_material);
					_waterMaterial.renderQueue = 2901;
					_waterDirty = false;
				}
				SetView(_material, cam);
				SetView(_waterMaterial, cam);
				DrawWater(cam);
			}
			else if (_reflections && (int)cam.cameraType == 16)
			{
				Material probeMaterial = _probeMaterial;
				cam.depthTextureMode = (DepthTextureMode)(cam.depthTextureMode | 1);
				if (_probeDirty)
				{
					SyncProbe();
					_probeDirty = false;
				}
				SetView(probeMaterial, cam);
			}
		}

		private void DrawWater(Camera cam)
		{
			//IL_0041: 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_0050: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			int i;
			for (i = 0; i < 31 && (cam.cullingMask & (1 << i)) == 0; i++)
			{
			}
			RenderParams val = default(RenderParams);
			((RenderParams)(ref val))..ctor(_waterMaterial);
			((RenderParams)(ref val)).camera = cam;
			((RenderParams)(ref val)).layer = i;
			((RenderParams)(ref val)).worldBounds = new Bounds(((Component)cam).transform.position, Vector3.one * 10f);
			((RenderParams)(ref val)).shadowCastingMode = (ShadowCastingMode)0;
			((RenderParams)(ref val)).receiveShadows = false;
			((RenderParams)(ref val)).lightProbeUsage = (LightProbeUsage)0;
			((RenderParams)(ref val)).reflectionProbeUsage = (ReflectionProbeUsage)0;
			((RenderParams)(ref val)).motionVectorMode = (MotionVectorGenerationMode)2;
			RenderParams val2 = val;
			Graphics.RenderPrimitives(ref val2, (MeshTopology)0, 3, 1);
		}

		private void SetView(Material m, Camera cam)
		{
			//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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_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_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_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)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00ac: 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)
			Vector3 position = ((Component)cam).transform.position;
			m.SetVector(CameraId, new Vector4(position.x, position.y, position.z, position.y - _water));
			int forwardId = ForwardId;
			Matrix4x4 cameraToWorldMatrix = cam.cameraToWorldMatrix;
			m.SetVector(forwardId, Vector4.op_Implicit(-Vector4.op_Implicit(((Matrix4x4)(ref cameraToWorldMatrix)).GetColumn(2))));
			CameraRays.Corners(cam, out var ray, out var ray2, out var ray3, out var ray4);
			m.SetVector(Ray00Id, Vector4.op_Implicit(ray));
			m.SetVector(Ray10Id, Vector4.op_Implicit(ray2));
			m.SetVector(Ray01Id, Vector4.op_Implicit(ray3));
			m.SetVector(Ray11Id, Vector4.op_Implicit(ray4));
		}
	}
	internal sealed class AirModule : IWeatherModule
	{
		private static readonly int CloudAirId = Shader.PropertyToID("_WO_CloudAir");

		private const string AirShader = "Hidden/WeatherOverhaul/Air";

		private const string AirWaterShader = "Hidden/WeatherOverhaul/AirWater";

		private readonly AirConfig _cfg;

		private readonly ShaderLibrary _shaders;

		private readonly FramePipeline _pipeline;

		private readonly ILog _log;

		private readonly SkyModule _sky;

		private static readonly int GameLightId = Shader.PropertyToID("_SunDir");

		private static readonly int SunFogId = Shader.PropertyToID("_SunFogColor");

		private Color _builtInFog;

		private Color _builtInSunFog;

		private const float BuiltInFogSeconds = 0.25f;

		private bool _builtInFromSky;

		private float _gameLight;

		private float _gameSky;

		private static readonly int FogHeightMinId = Shader.PropertyToID("_FogHeightMin");

		private static readonly int FogHeightMaxId = Shader.PropertyToID("_FogHeightMax");

		private readonly TerrainReach _reach = new TerrainReach();

		private readonly VanillaAir _vanilla = new VanillaAir();

		private readonly AirEase _ease = new AirEase();

		private AirFog _fog;

		private const string VolumeCompute = "Volumetric";

		private SunShadowCapture _capture;

		private VolumetricBuffer _volume;

		private HardwareTier _tier;

		private bool _computeWarned;

		private float _near;

		private float _nearReach = 200f;

		private double _driftX;

		private double _driftZ;

		private AirLayer _haze;

		private AirLayer _mist;

		private AirLayer _sea;

		private float _seaShare;

		private float _seaSampled = float.NegativeInfinity;

		private const float SeaSampleSeconds = 0.25f;

		private float _water = 30f;

		private bool _active;

		private readonly HandlerFailure _fogFailure = new HandlerFailure();

		private readonly Action _writeGameFog;

		public string Name => "Air";

		public bool ConfigEnabled => _cfg.Enabled.Value;

		public string[] ShadersRequired { get; } = new string[2] { "Hidden/WeatherOverhaul/Air", "Hidden/WeatherOverhaul/AirWater" };

		public OwnershipFlags Owns
		{
			get
			{
				if (!_active)
				{
					return OwnershipFlags.None;
				}
				return OwnershipFlags.Fog;
			}
		}

		public AirModule(AirConfig cfg, ShaderLibrary shaders, FramePipeline pipeline, ILog log, SkyModule sky)
		{
			_cfg = cfg;
			_shaders = shaders;
			_pipeline = pipeline;
			_log = log;
			_sky = sky;
			_writeGameFog = _fogFailure.Guard(WriteGameFog);
		}

		public void Enable()
		{
			_ease.Reset();
			_fog = new AirFog(_shaders.Find("Hidden/WeatherOverhaul/Air"), _shaders.Find("Hidden/WeatherOverhaul/AirWater"), _pipeline);
			_fogFailure.Clear();
			EnvManFogPatch.Captured += _writeGameFog;
			AirShared.Style = _cfg.Style.Value;
			ComputeShader val = _shaders.FindCompute("Volumetric");
			Texture val2 = _shaders.FindTexture("PerlinNoise32RGB");
			if (SystemInfo.supportsComputeShaders && (Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null)
			{
				_capture = new SunShadowCapture(val);
				_volume = new VolumetricBuffer(val, val2, _pipeline, _capture);
				_volume.Prepared += delegate(VolumetricBuffer v)
				{
					_fog?.SetVolume(v);
				};
			}
			else if (!_computeWarned)
			{
				_computeWarned = true;
				_log.Warn("[air] no compute shaders (or no volumetric shader in the bundle): light shafts are off, the analytic air stays.");
			}
			BuiltInFog.Air = _cfg;
		}

		public void Disable()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			BuiltInFog.Air = null;
			EnvManFogPatch.Captured -= _writeGameFog;
			_active = false;
			Shader.SetGlobalVector(CloudAirId, Vector4.zero);
			_sky.FogSkyWanted = false;
			_builtInFromSky = false;
			AirShared.Style = AirStyle.Earth;
			Safely("fog pass", delegate
			{
				_fog?.Destroy();
			});
			Safely("volumetric light", delegate
			{
				_volume?.Destroy();
				_capture?.Release();
			});
			_volume = null;
			_capture = null;
			WeatherDiagnostics.AirVolumetric = false;
			Safely("post-processing fog", delegate
			{
				_vanilla.Release();
			});
			Safely("built-in fog", delegate
			{
				//IL_0012: 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 (EnvManFogPatch.Have)
				{
					RenderSettings.fogDensity = EnvManFogPatch.VanillaDensity;
					RenderSettings.fogColor = EnvManFogPatch.VanillaFog;
					Shader.SetGlobalColor(SunFogId, EnvManFogPatch.VanillaSunFog);
				}
			});
			_fog = null;
			WeatherDiagnostics.AirActive = false;
			WeatherDiagnostics.AirPostFogOff = false;
		}

		public void ApplyProfile(HardwareTier tier)
		{
			_tier = tier;
		}

		public void Tick(in WeatherState s)
		{
			//IL_0059: 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_009b: 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_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: 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_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Invalid comparison between Unknown and I4
			//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_032d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0490: Unknown result type (might be due to invalid IL or missing references)
			//IL_0495: Unknown result type (might be due to invalid IL or missing references)
			//IL_0499: 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)
			//IL_04a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0670: 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_0674: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0500: Unknown result type (might be due to invalid IL or missing references)
			//IL_0535: 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_0559: Unknown result type (might be due to invalid IL or missing references)
			//IL_0560: Unknown result type (might be due to invalid IL or missing references)
			//IL_0565: Unknown result type (might be due to invalid IL or missing references)
			//IL_056c: Unknown result type (might be due to invalid IL or missing references)
			//IL_058b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0590: Unknown result type (might be due to invalid IL or missing references)
			//IL_0597: Unknown result type (might be due to invalid IL or missing references)
			//IL_059c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0836: 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)
			//IL_083b: Unknown result type (might be due to invalid IL or missing references)
			//IL_086a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0864: Unknown result type (might be due to invalid IL or missing references)
			//IL_086f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ae5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0904: Unknown result type (might be due to invalid IL or missing references)
			//IL_0906: Unknown result type (might be due to invalid IL or missing references)
			//IL_090d: Unknown result type (might be due to invalid IL or missing references)
			//IL_090f: Unknown result type (might be due to invalid IL or missing references)
			//IL_093d: Unknown result type (might be due to invalid IL or missing references)
			//IL_093f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0946: Unknown result type (might be due to invalid IL or missing references)
			//IL_0948: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b41: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_09b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_09b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_09ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_099c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bc6: Unknown result type (might be due to invalid IL or missing references)
			//IL_09bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bd6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bdb: 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_0be8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c02: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c09: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c10: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c17: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a10: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a02: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bbf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a15: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a49: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a4e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a7f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a84: Unknown result type (might be due to invalid IL or missing references)
			_fogFailure.ThrowIfFailed("the game's fog handler");
			AirShared.Style = _cfg.Style.Value;
			Camera camera = _pipeline.Camera;
			if (s.Forced || s.CameraUnderWater || (Object)(object)camera == (Object)null)
			{
				_active = false;
				Shader.SetGlobalVector(CloudAirId, Vector4.zero);
				_sky.FogSkyWanted = false;
				_builtInFromSky = false;
				_fog.Show(on: false);
				_fog.SetShafts(null);
				_fog.SetVolume(null, Vector4.zero, Vector4.zero, 0f, 0, on: false);
				_volume?.Show(on: false);
				_capture?.Tick(null);
				_vanilla.Release();
				WeatherDiagnostics.AirVolumetric = false;
				WeatherDiagnostics.AirActive = false;
				WeatherDiagnostics.AirPostFogOff = false;
				return;
			}
			_water = (((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.m_waterLevel : 30f);
			float fog = s.Fog;
			float view = Visibility.Of(fog, _cfg.VisibilityScale.Value * s.Tune.Visibility, s.Environment);
			float mist = HeightFog.MistAmount(s.DayFraction, WeatherDiagnostics.AirMistOverride ?? s.Variation.MorningMist, s.Rain, s.SnowFall);
			if (WeatherDiagnostics.SnapTransitions)
			{
				_ease.Reset();
			}
			_ease.Step(view, Visibility.HeightOf(s.Rain, s.SnowFall, fog), mist, Time.deltaTime, SeaTarget(((Component)camera).transform.position, s.Rain, s.SnowFall));
			float view2 = _ease.View;
			float mist2 = _ease.Mist;
			_haze = HeightFog.Haze(view2, _ease.Height);
			_mist = HeightFog.Mist(mist2);
			_sea = HeightFog.SeaMist(_ease.Sea, _cfg.SeaMistVisibility.Value, _cfg.SeaMistHeight.Value);
			_reach.Tick();
			DrawDistance.Safe(_reach.TerrainSize, _reach.UpdateStep, out var half, out var safe);
			float num;
			if (!((Object)(object)ZNet.instance != (Object)null) || !((Object)(object)ZoneSystem.instance != (Object)null))
			{
				num = DrawDistance.LodHideDistance(2, 64f);
			}
			else
			{
				SimulationDistance syncedSimulationDistance = ZNet.instance.GetSyncedSimulationDistance();
				num = DrawDistance.LodHideDistance(((SimulationDistance)(ref syncedSimulationDistance)).NearSimulationDistance, ZoneSystem.instance.m_zoneSize);
			}
			float num2 = num;
			bool flag = _sky.SkyDrawn && !WeatherDiagnostics.AirSkyHazeOff;
			_sky.FogSkyWanted = flag && !WeatherDiagnostics.FogSkyOff;
			Color val = (EnvManFogPatch.Have ? EnvManFogPatch.VanillaFog : RenderSettings.fogColor);
			Color val2 = (EnvManFogPatch.Have ? EnvManFogPatch.VanillaSunFog : val);
			if ((int)QualitySettings.activeColorSpace == 1)
			{
				val = ((Color)(ref val)).linear;
				val2 = ((Color)(ref val2)).linear;
			}
			int biome = SkyBiomes.Resolve(s.Biome, s.HasPlayer && WorldGenerator.IsAshlands(s.PlayerX, s.PlayerZ));
			float num3 = HeightFog.GameLightShare(biome);
			_gameLight = (WeatherDiagnostics.SnapTransitions ? num3 : Mathf.Lerp(_gameLight, num3, 1f - Mathf.Exp((0f - Time.deltaTime) / 3f)));
			float num4 = WeatherDiagnostics.AirGameSkyFog ?? HeightFog.GameSkyFogShare(biome);
			_gameSky = (WeatherDiagnostics.SnapTransitions ? num4 : Mathf.Lerp(_gameSky, num4, 1f - Mathf.Exp((0f - Time.deltaTime) / 3f)));
			Material skybox = RenderSettings.skybox;
			int num5;
			float num6;
			if ((Object)(object)skybox != (Object)null && skybox.HasProperty(FogHeightMinId))
			{
				num5 = (skybox.HasProperty(FogHeightMaxId) ? 1 : 0);
				if (num5 != 0)
				{
					num6 = skybox.GetFloat(FogHeightMinId);
					goto IL_0436;
				}
			}
			else
			{
				num5 = 0;
			}
			num6 = 0.05f;
			goto IL_0436;
			IL_0436:
			float gameSkyMin = num6;
			float gameSkyMax = ((num5 != 0) ? skybox.GetFloat(FogHeightMaxId) : 0.6f);
			bool builtInFromSky = _builtInFromSky;
			_builtInFromSky = false;
			if (flag && !WeatherDiagnostics.FogSkyOff && !WeatherDiagnostics.BuiltInFogSkyOff && _sky.FogSkyRim(out var rim))
			{
				Vector4 globalVector = Shader.GetGlobalVector(GameLightId);
				HeightFog.SkyRimFog(rim, globalVector.x, globalVector.z, SkyExposure.Luminance(new Rgb(val.r, val.g, val.b)), out var fog2, out var sunFog, !WeatherDiagnostics.BuiltInFogGameLevel);
				if (SkyExposure.Luminance(fog2) > 0f)
				{
					fog2 = Mix(fog2, val, _gameLight);
					sunFog = Mix(sunFog, val2, _gameLight);
					float num7 = (builtInFromSky ? (1f - Mathf.Exp((0f - Time.unscaledDeltaTime) / 0.25f)) : 1f);
					_builtInFog = Color.Lerp(_builtInFog, Gamma(new Color(fog2.R, fog2.G, fog2.B, 1f)), num7);
					_builtInSunFog = Color.Lerp(_builtInSunFog, Gamma(new Color(sunFog.R, sunFog.G, sunFog.B, 1f)), num7);
					_builtInFromSky = true;
				}
			}
			HeightFog.GlowDirection(s.SkySunDirX, s.SkySunDirY, s.SkySunDirZ, out var x, out var y, out var z);
			Vector3 sunDir = default(Vector3);
			((Vector3)(ref sunDir))..ctor(x, y, z);
			float num8 = num2;
			float num9 = HeightFog.FarRateFor(s.Rain, s.SnowFall, fog, _cfg.FarLandsHaze.Value);
			float mistCap = WeatherDiagnostics.AirMistCap ?? _cfg.MistLimit.Value;
			_fog.Set(_water, in _haze, in _mist, in _sea, mistCap, _reach.CenterX, _reach.CenterZ, half, safe, num2, flag && !WeatherDiagnostics.AirSkyPixelsOff, val, val2, sunDir, _reach.FarLands, num8, num9, _gameLight, _gameSky, gameSkyMin, gameSkyMax);
			float num10 = (EnvManFogPatch.Have ? EnvManFogPatch.VanillaDensity : RenderSettings.fogDensity);
			_near = Mathf.Min(num10, 0.006f) * Mathf.Max(0f, _cfg.NearHaze.Value);
			_nearReach = Mathf.Max(1f, _cfg.NearHazeDistance.Value);
			_fog.SetNear(_near, _nearReach);
			_fog.Show(on: true, _cfg.HazeInReflections.Value && !WeatherDiagnostics.AirReflectionsOff);
			_vanilla.Engage(camera);
			VolumeQuality q = AirProfile.With(AirProfile.For(_tier), _cfg.VolumetricLight.Value, _cfg.FogDistance.Value, _cfg.FogSlices.Value);
			bool flag2 = q.On && _volume != null;
			Light val3 = (((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.m_dirLight : null);
			if (flag2)
			{
				VolumeLight.Drift(ref _driftX, ref _driftZ, s.WindX, s.WindZ, Time.deltaTime);
				_driftX %= 5760.0;
				_driftZ %= 5760.0;
				_capture.Tick(val3);
				Vector3 val4 = ((((Vector3)(ref sunDir)).sqrMagnitude > 1E-06f) ? ((Vector3)(ref sunDir)).normalized : Vector3.up);
				Vector3 light = default(Vector3);
				((Vector3)(ref light))..ctor(s.SunDirX, s.SunDirY, s.SunDirZ);
				light = ((((Vector3)(ref light)).sqrMagnitude > 1E-06f) ? ((Vector3)(ref light)).normalized : val4);
				float num11 = VolumeLight.SunShare(((Object)(object)val3 != (Object)null) ? val3.intensity : 0f, s.GameLightIsMoon);
				Texture cookie = (((Object)(object)val3 != (Object)null) ? val3.cookie : null);
				VolumetricBuffer volume = _volume;
				VolumeInputs inputs = new VolumeInputs
				{
					Haze = _haze,
					Mist = _mist,
					Sea = _sea,
					MistCap = mistCap,
					Water = _water,
					FogLinear = val,
					SunFogLinear = val2,
					GameLight = _gameLight,
					Near = _near,
					NearReach = _nearReach,
					Glow = val4,
					Light = light,
					Share = num11,
					ShadowsOn = _capture.ShadowsOn,
					Shafts = (!WeatherDiagnostics.AirShaftsOff && _cfg.ShaftStrength.Value > 0f)
				};
				Color sunLinear;
				if (!((Object)(object)val3 != (Object)null))
				{
					sunLinear = Color.black;
				}
				else
				{
					Color val5 = val3.color * val3.intensity;
					sunLinear = ((Color)(ref val5)).linear;
				}
				inputs.SunLinear = sunLinear;
				inputs.PhaseG = _sky.MiePhaseG;
				inputs.ShaftStrength = _cfg.ShaftStrength.Value;
				inputs.Cookie = cookie;
				inputs.CookieMatrix = (((Object)(object)val3 != (Object)null) ? ((Component)val3).transform.worldToLocalMatrix : Matrix4x4.identity);
				inputs.CookieSize = (((Object)(object)val3 != (Object)null) ? val3.cookieSize : 1f);
				inputs.Wind = new Vector2((float)_driftX, (float)_driftZ);
				inputs.FogSky = _sky.FogSkyTexture;
				inputs.FogSkyRing = _sky.FogSkyRing;
				inputs.FogSkyParams = _sky.FogSkyParams;
				volume.Set(in q, in inputs);
				WeatherDiagnostics.AirVolumeShare = num11;
				WeatherDiagnostics.AirVolumeShadows = _capture.ShadowsOn;
			}
			else
			{
				_capture?.Tick(null);
			}
			_volume?.Show(flag2);
			if (!flag2)
			{
				_fog.SetShafts(null);
				_fog.SetVolume(null, Vector4.zero, Vector4.zero, 0f, 0, on: false);
			}
			WeatherDiagnostics.AirVolumetric = flag2;
			WeatherDiagnostics.AirVolumeRange = (flag2 ? _volume.Range : 0f);
			WeatherDiagnostics.AirVolumeSlices = (flag2 ? _volume.Slices : 0);
			_active = true;
			float aboveSea = ((Component)camera).transform.position.y - _water;
			float num12 = _haze.At(aboveSea) + (WeatherDiagnostics.CloudAirWithMist ? _mist.At(aboveSea) : 0f);
			Shader.SetGlobalVector(CloudAirId, (Vector4)(WeatherDiagnostics.CloudAirOff ? Vector4.zero : new Vector4(num12, Mathf.Max(0f, num8), _reach.FarLands ? Mathf.Clamp01(1f - num9) : 0f, 0f)));
			Vector3 position = ((Component)camera).transform.position;
			Vector3 forward = ((Component)camera).transform.forward;
			float num13 = DrawDistance.Edge(_reach.CenterX, _reach.CenterZ, half, position.x, position.z, forward.x, forward.z, safe);
			WeatherDiagnostics.AirActive = true;
			WeatherDiagnostics.AirSkyDrawn = flag;
			WeatherDiagnostics.AirPostFogOff = _vanilla.PostFogOff;
			WeatherDiagnostics.AirVisibility = view2;
			WeatherDiagnostics.AirHeight = _haze.Height;
			WeatherDiagnostics.AirMist = mist2;
			WeatherDiagnostics.AirSea = _ease.Sea;
			WeatherDiagnostics.AirDensityAtCamera = _haze.At(aboveSea) + _mist.At(aboveSea) + _sea.At(aboveSea);
			WeatherDiagnostics.AirFadeStart = 0.75f * num13;
			WeatherDiagnostics.AirFadeEnd = 0.97f * num13;
			WeatherDiagnostics.AirTerrainSize = _reach.TerrainSize;
			WeatherDiagnostics.AirLodHide = num2;
			WeatherDiagnostics.AirGameFog = EnvManFogPatch.VanillaDensity;
		}

		private void WriteGameFog()
		{
			//IL_0025: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			if (!_active)
			{
				return;
			}
			Camera camera = _pipeline.Camera;
			if (!((Object)(object)camera == (Object)null))
			{
				float aboveSea = ((Component)camera).transform.position.y - _water;
				RenderSettings.fogDensity = HeightFog.SeaViewDensity(in _haze, in _mist, in _sea, _near, _nearReach, aboveSea);
				if (_builtInFromSky)
				{
					RenderSettings.fogColor = _builtInFog;
					Shader.SetGlobalColor(SunFogId, _builtInSunFog);
				}
			}
		}

		private float SeaTarget(Vector3 eye, float rain, float snow)
		{
			//IL_009f: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			if (!_cfg.SeaMist.Value)
			{
				return 0f;
			}
			float num = (1f - Mathf.Clamp01(rain)) * (1f - Mathf.Clamp01(snow));
			if (!_cfg.SeaMistOnlyAtSea.Value)
			{
				return num;
			}
			if (Time.unscaledTime - _seaSampled >= 0.25f || Time.unscaledTime < _seaSampled)
			{
				_seaSampled = Time.unscaledTime;
				WorldGenerator instance = WorldGenerator.instance;
				if (instance != null)
				{
					int num2 = 0;
					for (int i = 0; i < 16; i++)
					{
						float num3 = (float)i * (MathF.PI / 8f);
						float num4 = Mathf.Cos(num3);
						float num5 = Mathf.Sin(num3);
						if (IsSea(instance, eye.x + num4 * 60f, eye.z + num5 * 60f))
						{
							num2++;
						}
						if (IsSea(instance, eye.x + num4 * 150f, eye.z + num5 * 150f))
						{
							num2++;
						}
					}
					_seaShare = (float)num2 / 32f;
				}
			}
			return HeightFog.SeaMistAmount(_seaShare) * num;
		}

		private bool IsSea(WorldGenerator world, float x, float z)
		{
			//IL_0009: 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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			Biome biome = world.GetBiome(x, z, 0.02f, false);
			if ((int)biome != 256)
			{
				if ((int)biome == 32)
				{
					return world.GetHeight(x, z) < _water - 1f;
				}
				return false;
			}
			return true;
		}

		private static Rgb Mix(Rgb sky, Color game, float share)
		{
			//IL_0006: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			return new Rgb(sky.R + (game.r - sky.R) * share, sky.G + (game.g - sky.G) * share, sky.B + (game.b - sky.B) * share);
		}

		private static Color Gamma(Color linear)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_000c: 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)
			if ((int)QualitySettings.activeColorSpace != 1)
			{
				return linear;
			}
			return ((Color)(ref linear)).gamma;
		}

		private void Safely(string what, Action action)
		{
			try
			{
				action();
			}
			catch (Exception ex)
			{
				_log.Warn("[air] " + what + " failed while shutting down: " + ex.GetType().Name + ": " + ex.Message);
			}
		}

		void IWeatherModule.Tick(in WeatherState state)
		{
			Tick(in state);
		}
	}
	internal static class AirPresets
	{
		public const float NorthOzone = 1.3f;

		public const float NorthMie = 0.6f;

		public static AtmosphereParams Base(AirStyle style)
		{
			AtmosphereParams earth = AtmospherePresets.Earth;
			if (style != AirStyle.North)
			{
				return earth;
			}
			earth.Ozone *= 1.3f;
			earth.MieScattering *= 0.6f;
			earth.MieAbsorption *= 0.6f;
			return earth;
		}
	}
	internal struct VolumeQuality
	{
		public bool On;

		public float Range;

		public int Slices;
	}
	internal static class AirProfile
	{
		public const float MinRange = 16f;

		public const float MaxRange = 1024f;

		public const int MinSlices = 16;

		public const int MaxSlices = 128;

		public static VolumeQuality For(HardwareTier tier)
		{
			return tier switch
			{
				HardwareTier.Medium => new VolumeQuality
				{
					On = true,
					Range = 128f,
					Slices = 48
				}, 
				HardwareTier.High => new VolumeQuality
				{
					On = true,
					Range = 256f,
					Slices = 64
				}, 
				HardwareTier.Ultra => new VolumeQuality
				{
					On = true,
					Range = 512f,
					Slices = 96
				}, 
				_ => new VolumeQuality
				{
					On = false,
					Range = 128f,
					Slices = 48
				}, 
			};
		}

		public static VolumeQuality With(VolumeQuality q, bool enabled, float distance, int slices)
		{
			bool flag = distance > 0f && !float.IsNaN(distance);
			bool flag2 = slices > 0;
			q.On = enabled && (q.On || flag || flag2);
			if (flag)
			{
				q.Range = Math.Min(1024f, Math.Max(16f, distance));
			}
			if (flag2)
			{
				q.Slices = Math.Min(128, Math.Max(16, slices));
			}
			return q;
		}
	}
	internal static class AirShared
	{
		public static AirStyle Style = AirStyle.Earth;
	}
	internal static class DrawDistance
	{
		public const float DefaultTerrainSize = 2400f;

		public const float DefaultUpdateStep = 256f;

		public const float StartFraction = 0.75f;

		public const float EndFraction = 0.97f;

		public const float MinEdge = 200f;

		public const float LodDepth = 1f;

		public static float LodHideDistance(int nearSimulationDistance, float zoneSize)
		{
			return (float)Math.Max(1, nearSimulationDistance) * (float)Math.Sqrt(2.0 * (double)zoneSize * (double)zoneSize);
		}

		public static float LodHaze(float horizontal, float lodHide, float edge)
		{
			if (!(edge > lodHide + 1f) || float.IsNaN(horizontal))
			{
				return 0f;
			}
			return 1f * Math.Min(1f, Math.Max(0f, (horizontal - lodHide) / (edge - lodHide)));
		}

		public static void Safe(float terrainSize, float updateStep, out float half, out float safe)
		{
			if (!(terrainSize > 0f) || float.IsInfinity(terrainSize))
			{
				terrainSize = 2400f;
			}
			if (!(updateStep >= 0f) || float.IsInfinity(updateStep))
			{
				updateStep = 256f;
			}
			half = terrainSize * 0.5f;
			safe = Math.Max(200f, half - updateStep);
		}

		public static float Edge(float centerX, float centerZ, float half, float camX, float camZ, float dirX, float dirZ, float safe)
		{
			if (float.IsNaN(centerX + centerZ + half + camX + camZ) || !(half > 0f))
			{
				return safe;
			}
			float num = camX - centerX;
			float num2 = camZ - centerZ;
			if (Math.Abs(num) >= half || Math.Abs(num2) >= half)
			{
				return safe;
			}
			float num3 = (float)Math.Sqrt(dirX * dirX + dirZ * dirZ);
			if (!(num3 > 0.0001f))
			{
				return half;
			}
			float num4 = dirX / num3;
			float num5 = dirZ / num3;
			float num6 = float.MaxValue;
			if (Math.Abs(num4) > 1E-06f)
			{
				num6 = Math.Min(num6, (((num4 > 0f) ? half : (0f - half)) - num) / num4);
			}
			if (Math.Abs(num5) > 1E-06f)
			{
				num6 = Math.Min(num6, (((num5 > 0f) ? half : (0f - half)) - num2) / num5);
			}
			return num6;
		}
	}
	internal static class FarLandsBridge
	{
		private static bool _probed;

		private static Func<bool> _active;

		private static Func<float> _centerX;

		private static Func<float> _centerZ;

		private static Func<float> _size;

		private static Func<float> _step;

		private static string _mismatch;

		internal static bool TryRead(out float centerX, out float centerZ, out float size, out float step, out string error)
		{
			centerX = (centerZ = (size = (step = 0f)));
			error = null;
			Probe();
			if (_mismatch != null)
			{
				error = _mismatch;
				_mismatch = null;
			}
			if (_active == null)
			{
				return false;
			}
			try
			{
				if (!_active())
				{
					return false;
				}
				centerX = _centerX();
				centerZ = _centerZ();
				size = _size();
				step = _step();
				return size > 0f && !float.IsNaN(centerX + centerZ + size + step) && !float.IsInfinity(centerX + centerZ + size + step);
			}
			catch (Exception ex)
			{
				_active = null;
				error = ex.GetType().Name + ": " + ex.Message;
				return false;
			}
		}

		internal static void Reset()
		{
			_probed = false;
			_active = null;
			_mismatch = null;
		}

		private static void Probe()
		{
			if (_probed)
			{
				return;
			}
			_probed = true;
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Type type;
				try
				{
					type = assembly.GetType("FarLands.FarLandsReach");
				}
				catch
				{
					continue;
				}
				if (!(type == null))
				{
					Func<bool> func = Getter<bool>(type, "Active");
					Func<float> func2 = Getter<float>(type, "CenterX");
					Func<float> func3 = Getter<float>(type, "CenterZ");
					Func<float> func4 = Getter<float>(type, "Size");
					Func<float> func5 = Getter<float>(type, "UpdateStep");
					if (func == null || func2 == null || func3 == null || func4 == null || func5 == null)
					{
						_mismatch = assembly.GetName().Name + "'s FarLandsReach lacks Active, CenterX, CenterZ, Size or UpdateStep";
						break;
					}
					_centerX = func2;
					_centerZ = func3;
					_size = func4;
					_step = func5;
					_active = func;
					break;
				}
			}
		}

		private static Func<T> Getter<T>(Type type, string name)
		{
			MethodInfo methodInfo = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public)?.GetGetMethod();
			if (!(methodInfo != null) || !(methodInfo.ReturnType == typeof(T)))
			{
				return null;
			}
			return (Func<T>)Delegate.CreateDelegate(typeof(Func<T>), methodInfo);
		}
	}
	internal enum Haze
	{
		Clear,
		Light,
		Standard,
		Thick,
		Custom
	}
	internal readonly struct HazeValues : IEquatable<HazeValues>
	{
		public readonly float NearHaze;

		public readonly float NearHazeDistance;

		public readonly float FarLandsHaze;

		public HazeValues(float nearHaze, float nearHazeDistance, float farLandsHaze)
		{
			NearHaze = nearHaze;
			NearHazeDistance = nearHazeDistance;
			FarLandsHaze = farLandsHaze;
		}

		public bool Equals(HazeValues o)
		{
			if (Math.Abs(NearHaze - o.NearHaze) < 0.005f && Math.Abs(NearHazeDistance - o.NearHazeDistance) < 0.5f)
			{
				return Math.Abs(FarLandsHaze - o.FarLandsHaze) < 0.005f;
			}
			return false;
		}

		public override bool Equals(object o)
		{
			if (o is HazeValues o2)
			{
				return Equals(o2);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (int)NearHazeDistance;
		}
	}
	internal static class HazePresets
	{
		public const float NearHaze = 0.6f;

		public const float NearHazeDistance = 50f;

		public const float FarLandsHaze = 1f;

		public static HazeValues Get(Haze h)
		{
			return h switch
			{
				Haze.Clear => new HazeValues(0.4f, 290f, 0.15f), 
				Haze.Light => new HazeValues(0.55f, 290f, 0.35f), 
				Haze.Thick => new HazeValues(0.8f, 250f, 0.85f), 
				_ => new HazeValues(0.6f, 50f, 1f), 
			};
		}

		public static Haze Match(HazeValues v)
		{
			Haze[] array = new Haze[4]
			{
				Haze.Clear,
				Haze.Light,
				Haze.Standard,
				Haze.Thick
			};
			foreach (Haze haze in array)
			{
				if (Get(haze).Equals(v))
				{
					return haze;
				}
			}
			return Haze.Custom;
		}

		public static Haze OnLoad(Haze saved, bool inFile, HazeValues current, out bool apply)
		{
			Haze haze = Match(current);
			apply = inFile && saved != Haze.Custom && haze != Haze.Custom && haze != saved;
			if (!apply)
			{
				return haze;
			}
			return saved;
		}
	}
	internal struct AirLayer
	{
		public float Density;

		public float Height;

		public float At(float aboveSea)
		{
			return Density * (float)Math.Exp((0f - Math.Max(-200f, float.IsNaN(aboveSea) ? 0f : aboveSea)) / Math.Max(Height, 1f));
		}

		public float MeanToSea(float aboveSea)
		{
			float num = (float.IsNaN(aboveSea) ? 0f : aboveSea);
			float num2 = Math.Max(Height, 1f);
			if (num < 0.01f * num2)
			{
				return At(num);
			}
			return Density * (float)((double)num2 / (double)num * (1.0 - Math.Exp((double)(0f - num) / (double)num2)));
		}
	}
	internal static class HeightFog
	{
		public const float MistVisibility = 400f;

		public const float MistHeight = 25f;

		public const float NearHazeMaxGameFog = 0.006f;

		public const float FarRate = 0.17f;

		public const float SeaMistView = 1500f;

		public const float SeaMistLayerHeight = 150f;

		public const float SeaSampleNear = 60f;

		public const float SeaSampleFar = 150f;

		public const int SeaSamples = 16;

		public const float MistMaxDepth = 0.8f;

		public const float MoonGlowBelow = -0.15f;

		public const float SkyClearPower = 16f;

		public const float SkyFogFar = 1000f;

		public const float SkyFogMaxMip = 0.5f;

		public const float GameLightSeconds = 3f;

		public const float GameSkyFogMin = 0.05f;

		public const float GameSkyFogMax = 0.6f;

		public const int SkyFogLastMip = 6;

		public const float HazeGrey = 0f;

		public const int RimMipSize = 16;

		private static Rgb[] SkyRow = new Rgb[16];

		private static Rgb[] BlurredRow = new Rgb[4];

		public static double OpticalDepth(in AirLayer l, float aboveSea, float dirY, float distance)
		{
			if (!(distance > 0f) || !(l.Density > 0f) || float.IsInfinity(distance))
			{
				return 0.0;
			}
			double num = Math.Max(l.Height, 1f);
			double num2 = Math.Max(-40.0, (double)distance * (double)(float.IsNaN(dirY) ? 0f : dirY) / num);
			double num3 = ((Math.Abs(num2) < 0.0001) ? (1.0 - 0.5 * num2) : ((1.0 - Math.Exp(0.0 - num2)) / num2));
			return (double)(l.At(aboveSea) * distance) * num3;
		}

		public static float FarRateFor(float rain, float snow, float fog, float rate = 0.17f)
		{
			float num = Math.Max(Visibility.DenseShare(fog), Math.Max(Clamp01(rain), Clamp01(snow)));
			rate = Clamp01(rate);
			return rate + (1f - rate) * num;
		}

		public static double FarThinned(double toKnee, double total, float rate)
		{
			if (total > toKnee && rate < 1f)
			{
				return toKnee + (double)Math.Max(0f, rate) * (total - toKnee);
			}
			return total;
		}

		public static double NearOpticalDepth(float density, float reach, float distance)
		{
			if (!(density > 0f) || !(reach > 0f) || !(distance > 0f) || float.IsInfinity(density))
			{
				return 0.0;
			}
			if (float.IsInfinity(distance))
			{
				return (double)density * (double)reach;
			}
			return (double)density * (double)reach * (1.0 - Math.Exp((double)(0f - distance) / (double)reach));
		}

		public static double NearEquivalentDensity(float density, float reach)
		{
			if (!(reach > 0f))
			{
				return 0.0;
			}
			return NearOpticalDepth(density, reach, 2f * reach) / (2.0 * (double)reach);
		}

		public static AirLayer Haze(float view, float height)
		{
			return new AirLayer
			{
				Density = Visibility.Koschmieder(view),
				Height = height
			};
		}

		public static AirLayer Mist(float amount)
		{
			return new AirLayer
			{
				Density = Visibility.Koschmieder(400f) * amount,
				Height = 25f
			};
		}

		public static AirLayer SeaMist(float amount, float view = 1500f, float height = 150f)
		{
			return new AirLayer
			{
				Density = Visibility.Koschmieder(view) * Clamp01(amount),
				Height = height
			};
		}

		public static float SeaMistAmount(float waterShare)
		{
			return Smooth(0.4f, 0.85f, waterShare);
		}

		public static double MistDepth(double raw, float cap)
		{
			if (cap > 0f && raw > 0.0)
			{
				return (double)cap * (1.0 - Math.Exp((0.0 - raw) / (double)cap));
			}
			return Math.Max(raw, 0.0);
		}

		public static float BuiltInDensity(in AirLayer haze, in AirLayer mist, float near, float nearReach, float aboveSea, in AirLayer sea = default(AirLayer))
		{
			return haze.At(aboveSea) + mist.At(aboveSea) + sea.At(aboveSea) + (float)NearEquivalentDensity(near, nearReach);
		}

		public static float SeaViewDensity(in AirLayer haze, in AirLayer mist, in AirLayer sea, float near, float nearReach, float aboveSea)
		{
			return haze.MeanToSea(aboveSea) + mist.MeanToSea(aboveSea) + sea.MeanToSea(aboveSea) + (float)NearEquivalentDensity(near, nearReach);
		}

		public static void GlowDirection(float sx, float sy, float sz, out float x, out float y, out float z)
		{
			float num = (float)Math.Sqrt(sx * sx + sy * sy + sz * sz);
			if (!(num > 1E-05f))
			{
				x = 0f;
				y = 1f;
				z = 0f;
			}
			else
			{
				float num2 = ((sy / num < -0.15f) ? (-1f) : 1f);
				x = num2 * sx / num;
				y = num2 * sy / num;
				z = num2 * sz / num;
			}
		}

		public static float SkyHazeKept(float cosToLight)
		{
			if (!(cosToLight > 0f))
			{
				return 1f;
			}
			return 1f - (float)Math.Pow(Math.Min(1f, cosToLight), 16.0);
		}

		public static float GameLightShare(int biome)
		{
			return biome switch
			{
				512 => 1f, 
				32 => 0.5f, 
				_ => 0f, 
			};
		}

		public static float GameSkyFogShare(int biome)
		{
			if (biome != 512)
			{
				return 0f;
			}
			return 1f;
		}

		public static float GameSkyFog(float viewY, float min, float max)
		{
			if (float.IsNaN(viewY))
			{
				return 0f;
			}
			float num = ((max > min) ? Math.Min(1f, Math.Max(0f, (viewY - min) / (max - min))) : ((viewY < min) ? 0f : 1f));
			return 1f - num * num * (3f - 2f * num);
		}

		public static float SkyFogMip(float distance)
		{
			float num = ((distance > 0f) ? Math.Min(1f, distance / 1000f) : 0f);
			return (1f - 0.5f * num) * 6f;
		}

		public static float SkyFogScale(float ringLum, float gameLum)
		{
			if (!(ringLum > 0f) || !(gameLum > 0f) || float.IsInfinity(gameLum) || float.IsInfinity(ringLum))
			{
				return 0f;
			}
			return Math.Min(1f, gameLum / ringLum);
		}

		public static float HorizonLevel(float horizonLum, float mipRingLum)
		{
			if (!(horizonLum > 0f) || !(mipRingLum > 0f) || float.IsInfinity(horizonLum) || float.IsInfinity(mipRingLum))
			{
				return 1f;
			}
			return Math.Min(4f, Math.Max(0.25f, horizonLum / mipRingLum));
		}

		public static Rgb HazeColour(Rgb sky, float grey = 0f)
		{
			float num = SkyExposure.Luminance(sky);
			grey = Clamp01(grey);
			return sky * (1f - grey) + new Rgb(num, num, num) * grey;
		}

		public static void RimDirection(int x, int y, out float dx, out float dy, out float dz)
		{
			Direction(x, y, 16, out dx, out dy, out dz);
		}

		public static void SkyRimFog(Rgb[] mip, float lightX, float lightZ, float gameLum, out Rgb fog, out Rgb sunFog, bool skyLevel = false, float grey = 0f)
		{
			fog = default(Rgb);
			sunFog = default(Rgb);
			int num = 16;
			if (mip == null || mip.Length < num * num)
			{
				return;
			}
			double num2 = 0.0;
			for (int i = 0; i < num; i++)
			{
				num2 += (double)SkyExposure.Luminance(mip[i]);
			}
			float num3 = ((!skyLevel) ? SkyFogScale((float)(num2 / (double)num), gameLum) : ((num2 > 0.0) ? 1f : 0f));
			if (!(num3 > 0f))
			{
				return;
			}
			Rgb[] array;
			if (skyLevel)
			{
				array = ((SkyRow.Length == num) ? SkyRow : (SkyRow = new Rgb[num]));
				Array.Copy(mip, array, num);
			}
			else
			{
				array = ((BlurredRow.Length == num / 4) ? Bl