Decompiled source of ImmersiveCameraEnhanced v1.0.0

BepInEx/plugins/ImmersiveCameraEnhanced/ImmersiveCameraEnhanced.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[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("ImmersiveCameraEnhanced")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ImmersiveCameraEnhanced")]
[assembly: AssemblyTitle("ImmersiveCameraEnhanced")]
[assembly: AssemblyVersion("1.0.0.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 CameraCull
{
	internal sealed class ConfigurationManagerAttributes
	{
		public string Category;

		public string DispName;

		public int? Order;

		public bool? Browsable;
	}
	[BepInPlugin("com.kimbauer.valheim.cameracull", "Immersive Camera Enhanced", "1.0.0")]
	[BepInProcess("valheim.exe")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "com.kimbauer.valheim.cameracull";

		public const string Version = "1.0.0";

		internal static Plugin Instance;

		internal static CameraCullController Controller;

		internal static ConfigEntry<int> CameraCollisionMask;

		internal static ConfigEntry<bool> EnableMod;

		internal static ConfigEntry<bool> EnableCylinderOcclusion;

		internal static ConfigEntry<float> CylinderCameraWidthPercent;

		internal static ConfigEntry<float> ConeCharacterDistance;

		internal static ConfigEntry<bool> CullHousePillars;

		internal static ConfigEntry<bool> LeavesOnly;

		internal static ConfigEntry<bool> MovementLeavesOnly;

		internal static ConfigEntry<float> MovementLeavesOnlyActivationDelay;

		internal static ConfigEntry<bool> EnableFirstPersonCamera;

		internal static ConfigEntry<bool> EnableFirstPersonCameraSway;

		internal static ConfigEntry<bool> EnableFirstPersonCameraAnimations;

		internal static ConfigEntry<float> FirstPersonCameraFov;

		internal static ConfigEntry<bool> EnableCameraZoom;

		internal static ConfigEntry<KeyboardShortcut> CameraZoomKey;

		internal static ConfigEntry<float> CameraZoomDefaultMagnification;

		internal static ConfigEntry<float> CameraZoomMagnificationStep;

		internal static ConfigEntry<float> CameraZoomMaxMagnification;

		internal static ConfigEntry<float> CameraZoomSmoothSpeed;

		internal static ConfigEntry<float> CameraZoomMouseSensitivityFactor;

		internal static ConfigEntry<float> CameraDistanceSmoothSpeed;

		internal static ConfigEntry<bool> EnableFirstPersonFreeLook;

		internal static ConfigEntry<KeyboardShortcut> FirstPersonFreeLookKey;

		internal static ConfigEntry<bool> EnableAdvancedCamera;

		internal static ConfigEntry<float> AdvancedCameraCeilingCheckInterval;

		internal static ConfigEntry<bool> EnableAdvancedCameraHeightClearance;

		internal static ConfigEntry<float> AdvancedCameraClearance;

		internal static ConfigEntry<float> ThirdPersonCameraDistance;

		internal static ConfigEntry<float> BoatCameraDistance;

		internal static ConfigEntry<bool> IgnoreVegetationCollision;

		internal static ConfigEntry<bool> IgnoreHousePillarCollision;

		internal static ConfigEntry<bool> IgnoreHouseLightCollision;

		internal static ConfigEntry<bool> IgnoreEntityCollision;

		internal static ConfigEntry<bool> KeepFoundationFloorRoofCollision;

		internal static ConfigEntry<float> BackCylinderLength;

		internal static ConfigEntry<float> ConeGrowthExponent;

		internal static ConfigEntry<float> ConeRearRadiusMultiplier;

		internal static ConfigEntry<float> CylinderVerticalFlattenPercent;

		internal static ConfigEntry<bool> CylinderFlattenBottom;

		internal static ConfigEntry<float> CylinderHorizontalFlattenPercent;

		internal static ConfigEntry<float> CylinderTopFlattenPercent;

		internal static ConfigEntry<float> CylinderSlicesPerMeter;

		internal static ConfigEntry<float> CylinderExponentInfluencePercent;

		internal static ConfigEntry<float> CylinderCheckInterval;

		internal static ConfigEntry<float> CylinderRestoreDelay;

		internal static ConfigEntry<bool> PreserveVegetationShadows;

		internal static ConfigEntry<bool> EnableBrightnessAdjustment;

		internal static ConfigEntry<float> DayBrightnessPercent;

		internal static ConfigEntry<float> NightBrightnessPercent;

		internal static ConfigEntry<float> FogCaveBrightnessPercent;

		internal static ConfigEntry<string> VegetationNameTokens;

		internal static ConfigEntry<string> ProtectedNameTokens;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ConfigEntry<bool> ShowOcclusionCylinder;

		internal static ConfigEntry<float> CylinderDebugOpacity;

		private Harmony harmony;

		internal static bool ModEnabled
		{
			get
			{
				if (EnableMod != null)
				{
					return EnableMod.Value;
				}
				return false;
			}
		}

		private static ConfigDescription UiDescription(string description, string category, int order, string displayName = null, AcceptableValueBase acceptableValues = null)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			return new ConfigDescription(description, acceptableValues, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Category = category,
					Order = order,
					DispName = displayName
				}
			});
		}

		private void Awake()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Expected O, but got Unknown
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Invalid comparison between Unknown and I4
			//IL_0562: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b3: Expected O, but got Unknown
			//IL_0a4f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a59: Expected O, but got Unknown
			//IL_0cac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0cb6: Expected O, but got Unknown
			//IL_0ec1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ec6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ecc: Expected O, but got Unknown
			//IL_0edc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ee6: Expected O, but got Unknown
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "Enabled", true, new ConfigDescription("Legacy key retained for migration.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Category = "99 - Legacy",
					Order = -100,
					Browsable = false
				}
			}));
			EnableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "EnableMod", val.Value, UiDescription("Master switch. When disabled, the cylinder, visual culling, and camera collision filtering are inactive.", "00 - Camera Cull", 110, "Enable Immersive Camera Enhanced"));
			EnableCylinderOcclusion = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "EnableCameraCull", val.Value, UiDescription("Enable or disable V1 cylinder visual culling. The global Enable Mod switch controls the whole mod.", "00 - Camera Cull", 100, "Enable Cylinder Occlusion"));
			LeavesOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "LeavesOnly", false, UiDescription("V1 only: hides identified leaves on large trees; trunks and branches remain visible.", "00 - Camera Cull", 90, "Leaves Only"));
			MovementLeavesOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "MovementLeavesOnly", true, UiDescription("Temporarily uses Leaves Only while the character walks toward the camera. Direction detection is local and does not scan the scene.", "00 - Camera Cull", 80, "Leaves Only While Moving Toward Camera"));
			((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "MovementLeavesOnlyDuration", 1.5f, new ConfigDescription("Legacy value retained for compatibility; it is not used as the activation delay.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Category = "99 - Legacy",
					Order = -70,
					Browsable = false
				}
			}));
			MovementLeavesOnlyActivationDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "MovementLeavesOnlyActivationDelay", 0.5f, UiDescription("Continuous movement time toward the camera before Leaves Only becomes active.", "00 - Camera Cull / Adjustments", 120, "Movement Leaves Only Activation Delay", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f)));
			EnableFirstPersonCamera = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "EnableFirstPersonCamera", true, UiDescription("Enables vanilla first person when the scroll reaches the minimum zoom. Scroll away from the minimum to return to third person. This client setting does not change the vanilla first-person camera.", "20 - Camera Improvements", 100, "Enable Vanilla First Person"));
			EnableFirstPersonCameraSway = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "EnableFirstPersonCameraSway", true, UiDescription("Adds a lightweight first-person movement sway by rotating the camera only. It never repositions the camera.", "20 - Camera Improvements", 90, "Enable First Person Camera Sway"));
			EnableFirstPersonCameraAnimations = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "EnableFirstPersonCameraAnimations", true, UiDescription("Enables first-person character camera animation. Crouching smoothly lowers the camera by 30% of the character height.", "20 - Camera Improvements", 80, "Enable First Person Camera Animations"));
			FirstPersonCameraFov = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "FirstPersonCameraFov", 65f, UiDescription("Local field of view used only while vanilla first person is active. This client value overrides server and external camera settings.", "20 - Camera Improvements / Adjustments", 70, "First Person Camera FOV", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 120f)));
			EnableCameraZoom = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "EnableCameraZoom", true, UiDescription("Hold the configured key to magnify the view toward the crosshair in third or first person. The wheel adjusts magnification while held; releasing the key restores the normal view.", "20 - Camera Improvements", 60, "Enable Hold-to-Zoom"));
			CameraZoomKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Camera", "CameraZoomKey", new KeyboardShortcut((KeyCode)326, Array.Empty<KeyCode>()), UiDescription("Key held for temporary camera zoom. The default is Mouse4 (Unity Mouse3).", "20 - Camera Improvements", 50, "Zoom Hold Key"));
			KeyboardShortcut value = CameraZoomKey.Value;
			bool flag = false;
			using (IEnumerator<KeyCode> enumerator = ((KeyboardShortcut)(ref value)).Modifiers.GetEnumerator())
			{
				if (enumerator.MoveNext())
				{
					_ = enumerator.Current;
					flag = true;
				}
			}
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 325 && !flag)
			{
				CameraZoomKey.Value = new KeyboardShortcut((KeyCode)326, Array.Empty<KeyCode>());
			}
			CameraZoomDefaultMagnification = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "CameraZoomDefaultMagnification", 2f, UiDescription("Initial optical magnification when the zoom key is held.", "20 - Camera Improvements / Adjustments", 70, "Default Zoom Magnification", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 40f)));
			CameraZoomMagnificationStep = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "CameraZoomMagnificationStep", 0.5f, UiDescription("Change in optical magnification per scroll notch while the zoom key is held.", "20 - Camera Improvements / Adjustments", 60, "Zoom Magnification per Scroll", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f)));
			CameraZoomMaxMagnification = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "CameraZoomMaxMagnification", 20f, UiDescription("Maximum optical magnification while zooming. Values up to 40 are supported.", "20 - Camera Improvements / Adjustments", 50, "Maximum Zoom Magnification", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 40f)));
			CameraZoomSmoothSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "CameraZoomSmoothSpeed", 14f, UiDescription("Speed used to smooth optical zoom changes while the zoom key is held.", "20 - Camera Improvements / Adjustments", 45, "Zoom Smooth Speed", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 40f)));
			CameraZoomMouseSensitivityFactor = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "CameraZoomMouseSensitivityFactor", 0.2f, UiDescription("Multiplier applied to mouse sensitivity while zooming. Lower values slow the view more; 0.20 is five times slower than the unscaled response.", "20 - Camera Improvements / Adjustments", 42, "Zoom Mouse Sensitivity Factor", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 1f)));
			CameraDistanceSmoothSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "CameraDistanceSmoothSpeed", 12f, UiDescription("Speed used to smooth normal third-person distance changes from the scroll wheel.", "20 - Camera Improvements / Adjustments", 40, "Camera Distance Smooth Speed", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 40f)));
			EnableFirstPersonFreeLook = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "EnableFirstPersonFreeLook", true, UiDescription("Allows looking around freely while the configured Alt key is held without changing the character's movement direction.", "20 - Camera Improvements", 40, "Enable Alt Free Look"));
			FirstPersonFreeLookKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Camera", "FirstPersonFreeLookKey", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), UiDescription("Key held for free look. The default is Left Alt.", "20 - Camera Improvements", 30, "Free Look Hold Key"));
			EnableAdvancedCamera = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "EnableAdvancedCamera", true, UiDescription("Keeps third-person camera height within the clear space between ground and ceiling while vertical look rotates toward the crosshair.", "20 - Camera Improvements", 20, "Enable Advanced Camera"));
			AdvancedCameraCeilingCheckInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "AdvancedCameraCeilingCheckInterval", 2f, UiDescription("How often the client checks for a player-built ceiling above the current camera position.", "20 - Camera Improvements / Adjustments", 35, "Advanced Camera Ceiling Check Interval", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f)));
			EnableAdvancedCameraHeightClearance = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera", "EnableAdvancedCameraHeightClearance", true, UiDescription("Allows Advanced Camera to move vertically inside the available floor-to-ceiling space while preserving clearance.", "20 - Camera Improvements", 15, "Enable Advanced Camera Height Clearance"));
			AdvancedCameraClearance = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "AdvancedCameraClearance", 6f, UiDescription("Minimum clearance in metres from the floor and ceiling while height clearance is active.", "20 - Camera Improvements / Adjustments", 30, "Advanced Camera Clearance", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 10f)));
			ThirdPersonCameraDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "ThirdPersonCameraDistance", 6f, UiDescription("Maximum local third-person distance for the character. This client value overrides server-side camera distance settings.", "20 - Camera Improvements / Adjustments", 80, "Third Person Camera Distance", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 35f)));
			BoatCameraDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Camera", "BoatCameraDistance", 6f, UiDescription("Maximum local camera distance while controlling a boat. This client value overrides server-side camera distance settings.", "20 - Camera Improvements / Adjustments", 70, "Boat Camera Distance", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 35f)));
			CullHousePillars = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "CullHousePillars", true, UiDescription("Also hides player-built support pillars and stone arches that intersect the cylinder.", "00 - Camera Cull", 70, "Cull Supports & Stone Arches"));
			IgnoreVegetationCollision = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "IgnoreVegetationCollision", true, UiDescription("Prevents camera collision from stopping on recognized vegetation.", "10 - Camera Collision", 100, "Ignore Vegetation Collision"));
			((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "IgnoreRockCollision", false, new ConfigDescription("Legacy key retained for migration. Terrain, rocks, ores, and boulders always stop the camera.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Category = "99 - Legacy",
					Order = -90,
					Browsable = false
				}
			}));
			IgnoreHousePillarCollision = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "IgnoreHousePillarCollision", true, UiDescription("Allows the camera to pass through player-built support pillars and stone arches. Walls, foundations, floors, and roofs remain solid.", "10 - Camera Collision", 90, "Ignore Support & Arch Collision"));
			IgnoreHouseLightCollision = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "IgnoreHouseLightCollision", true, UiDescription("Allows the camera to pass through wall sconces, all torches, light fixtures, and tables.", "10 - Camera Collision", 80, "Ignore Props & Lights Collision"));
			IgnoreEntityCollision = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "IgnoreEntityCollision", true, UiDescription("Allows the camera to pass through players, animals, enemies, and other entities.", "10 - Camera Collision", 70, "Ignore Entity Collision"));
			KeepFoundationFloorRoofCollision = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "KeepFoundationFloorRoofCollision", true, UiDescription("Keeps structural walls, foundations, floors, ceilings, and roofs solid, with clearance below horizontal surfaces based on their thickness.", "10 - Camera Collision", 60, "Structural Surface Collision"));
			PreserveVegetationShadows = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "PreserveVegetationShadows", true, UiDescription("Hides vegetation color while keeping shadows.", "00 - Camera Cull", 60, "Preserve Vegetation Shadows"));
			CylinderCameraWidthPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "CylinderCameraWidthPercent", 25f, UiDescription("Camera-side width as a screen percentage; the apex closes to zero.", "00 - Camera Cull / Adjustments", 100, "Cylinder Camera Width", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f)));
			ConeCharacterDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "ConeCharacterDistance", 0.5f, UiDescription("Distance from the character center to the cylinder apex; the apex points toward the camera.", "00 - Camera Cull / Adjustments", 110, "Cylinder Character Distance", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f)));
			BackCylinderLength = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "BackCylinderLength", 10f, UiDescription("Additional cylinder length in metres beyond the camera.", "00 - Camera Cull / Adjustments", 90, "Cylinder Length Behind Camera", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f)));
			ConeGrowthExponent = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "ConeGrowthExponent", 2.4f, UiDescription("Cylinder radius curvature; values above 1 keep the start narrow and expand near the camera.", "00 - Camera Cull / Adjustments", 80, "Cylinder Growth Exponent", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 6f)));
			ConeRearRadiusMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "ConeRearRadiusMultiplier", 1.75f, UiDescription("Radius multiplier at the rear tip beyond the camera.", "00 - Camera Cull / Adjustments", 60, "Cylinder Rear Radius Multiplier", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 4f)));
			CylinderTopFlattenPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "CylinderTopFlattenPercent", 30f, new ConfigDescription("Legacy value migrated to CylinderVerticalFlattenPercent.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Category = "99 - Legacy",
					Order = -100,
					Browsable = false
				}
			}));
			CylinderVerticalFlattenPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "CylinderVerticalFlattenPercent", CylinderTopFlattenPercent.Value, UiDescription("Flattens the upper vertical side of the cylinder after applying the growth exponent.", "00 - Camera Cull / Adjustments", 40, "Cylinder Vertical Flatten", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f)));
			CylinderFlattenBottom = ((BaseUnityPlugin)this).Config.Bind<bool>("Camera occlusion", "CylinderFlattenBottom", false, UiDescription("Also applies the vertical flattening limit to the lower side of the cylinder.", "00 - Camera Cull / Adjustments", 30, "Flatten Bottom"));
			CylinderHorizontalFlattenPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "CylinderHorizontalFlattenPercent", 0f, UiDescription("Flattens the horizontal width of the cylinder after applying the growth exponent.", "00 - Camera Cull / Adjustments", 20, "Cylinder Horizontal Flatten", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f)));
			CylinderSlicesPerMeter = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "CylinderSlicesPerMeter", 2f, UiDescription("Curved-cylinder profile cuts per metre. Higher values make the stepped profile denser.", "00 - Camera Cull / Adjustments", 50, "Cylinder Cuts Per Metre", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 12f)));
			CylinderExponentInfluencePercent = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "CylinderExponentInfluencePercent", 100f, UiDescription("Percentage of the growth exponent applied at each profile cut.", "00 - Camera Cull / Adjustments", 70, "Growth Exponent Influence", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f)));
			CylinderCheckInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "CylinderCheckInterval", 0.6f, UiDescription("Seconds between cylinder contact checks. The cylinder transform still follows the camera every frame.", "90 - Performance", 100, "Cylinder Check Interval", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f)));
			CylinderRestoreDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Camera occlusion", "CylinderRestoreDelay", 0.6f, UiDescription("Seconds an object must remain outside the cylinder before it is restored. Set to 0 for immediate restoration.", "90 - Performance", 90, "Cylinder Restore Delay", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f)));
			EnableBrightnessAdjustment = ((BaseUnityPlugin)this).Config.Bind<bool>("Visual", "EnableBrightnessAdjustment", true, UiDescription("Enables the local darkness, cave, and fog brightness adjustment.", "30 - Visual", 100, "Enable Brightness Adjustment"));
			ConfigEntry<float> val2 = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "BrightnessBoostPercent", 25f, new ConfigDescription("Legacy value retained to migrate the separate night and fog/cave controls.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Category = "99 - Legacy",
					Order = -80,
					Browsable = false
				}
			}));
			DayBrightnessPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "DayBrightnessPercent", 0f, UiDescription("Signed daylight brightness. Negative values darken, zero keeps vanilla daylight, and values above 100 apply stronger HDR light.", "30 - Visual", 90, "Day Brightness", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-100f, 300f)));
			NightBrightnessPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "NightBrightnessPercent", val2.Value, UiDescription("Signed brightness used at night and by always-dark environments. Negative values darken; values above 100 apply stronger HDR light.", "30 - Visual", 80, "Night Brightness", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-100f, 300f)));
			FogCaveBrightnessPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Visual", "FogCaveBrightnessPercent", val2.Value, UiDescription("Signed brightness for dense fog, mist, caves, crypts, and dungeons. Negative values darken; values above 100 apply stronger HDR light.", "30 - Visual", 70, "Fog & Cave Brightness", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-100f, 300f)));
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, UiDescription("Writes diagnostic information to the BepInEx log.", "99 - Debug", 0));
			ShowOcclusionCylinder = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "ShowOcclusionCylinder", false, UiDescription("Draws the curved cylinder in green for calibration.", "99 - Debug", 1));
			CylinderDebugOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("Debug", "CylinderOpacity", 0.2f, UiDescription("Diagnostic outline opacity; 0 is invisible and 1 is fully opaque.", "99 - Debug", 2, "Cylinder Outline Opacity", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)));
			CameraCollisionMask = ((BaseUnityPlugin)this).Config.Bind<int>("Detection", "CollisionLayerMask", -1, UiDescription("Unity layer mask used by physical queries; -1 includes every layer.", "40 - Detection / Adjustments", 0, "Collision Layer Mask", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1, 31)));
			VegetationNameTokens = ((BaseUnityPlugin)this).Config.Bind<string>("Detection", "VegetationNameTokens", "tree,beech,birch,oak,pine,fir,ash,juniper,yggdrasil,stubbe,stump,treestump,tree_stump,ashlandstump,swamptree,sapling,bush,shrub,berry,raspberry,blueberry,cloudberry,mushroom,thistle,dandelion,grass,plant,fern,reed,vine,root,trunk,branch,treelog,treebase,foliage,leaf,leaves,flax,barley,carrot,turnip,onion", UiDescription("Comma-separated name fragments considered vegetation.", "40 - Detection / Adjustments", 1));
			ProtectedNameTokens = ((BaseUnityPlugin)this).Config.Bind<string>("Detection", "ProtectedNameTokens", "terrain,water,ocean,seafloor,sky,sun,moon,fog,minimap,map,loading,menu,ui,hud,player,character,creature,enemy,boss,vfx,particle,smoke,projectile,itemdrop,pickup,portal,rock,stone,boulder,ore,oredeposit,flint", UiDescription("Comma-separated name fragments excluded from camera occlusion detection.", "40 - Detection / Adjustments", 2));
			GameObject val3 = new GameObject("ImmersiveCameraEnhancedController");
			Object.DontDestroyOnLoad((Object)val3);
			Controller = val3.AddComponent<CameraCullController>();
			harmony = new Harmony("com.kimbauer.valheim.cameracull");
			PatchGameCamera();
			PatchEnvironmentManager();
			((BaseUnityPlugin)this).Logger.LogInfo((object)(ModEnabled ? "Immersive Camera Enhanced 1.0.0 loaded and active." : "Immersive Camera Enhanced 1.0.0 loaded, but disabled by Camera occlusion/EnableMod=false."));
		}

		private void PatchGameCamera()
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Expected O, but got Unknown
			//IL_0139: Expected O, but got Unknown
			//IL_0139: Expected O, but got Unknown
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Expected O, but got Unknown
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Expected O, but got Unknown
			//IL_021a: Expected O, but got Unknown
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Expected O, but got Unknown
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: Expected O, but got Unknown
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Expected O, but got Unknown
			//IL_0431: Unknown result type (might be due to invalid IL or missing references)
			//IL_043f: Expected O, but got Unknown
			//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b8: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("GameCamera");
				if (type == null)
				{
					Debug("GameCamera was not found; using only the render callback.");
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(type, "LateUpdate", (Type[])null, (Type[])null) ?? AccessTools.Method(type, "Update", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					Debug("No GameCamera update method was found.");
					return;
				}
				MethodInfo methodInfo2 = AccessTools.Method(typeof(GameCameraPatch), "Postfix", (Type[])null, (Type[])null);
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Debug("GameCamera patched at " + methodInfo.Name + ".");
				MethodInfo method = type.GetMethod("UpdateCamera", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(float) }, null);
				if (method != null)
				{
					MethodInfo methodInfo3 = AccessTools.Method(typeof(GameCameraPatch), "PrefixUpdateCamera", (Type[])null, (Type[])null);
					MethodInfo methodInfo4 = AccessTools.Method(typeof(GameCameraPatch), "PostfixUpdateCamera", (Type[])null, (Type[])null);
					MethodInfo methodInfo5 = AccessTools.Method(typeof(GameCameraPatch), "TranspileUpdateCamera", (Type[])null, (Type[])null);
					harmony.Patch((MethodBase)method, new HarmonyMethod(methodInfo3), new HarmonyMethod(methodInfo4), new HarmonyMethod(methodInfo5), (HarmonyMethod)null, (HarmonyMethod)null);
					Debug("Local camera distance limits patched.");
				}
				BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
				MethodInfo methodInfo6 = AccessTools.TypeByName("PlayerController")?.GetMethod("LateUpdate", bindingAttr, null, Type.EmptyTypes, null);
				if (methodInfo6 != null)
				{
					MethodInfo methodInfo7 = AccessTools.Method(typeof(GameCameraPatch), "TranspilePlayerControllerMouseInput", (Type[])null, (Type[])null);
					harmony.Patch((MethodBase)methodInfo6, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo7), (HarmonyMethod)null, (HarmonyMethod)null);
					Debug("Zoomed mouse sensitivity patched at PlayerController.LateUpdate.");
				}
				MethodInfo methodInfo8 = AccessTools.Method(type, "GetCameraPosition", (Type[])null, (Type[])null);
				if (methodInfo8 != null)
				{
					MethodInfo methodInfo9 = AccessTools.Method(typeof(GameCameraPatch), "PrefixGetCameraPosition", (Type[])null, (Type[])null);
					MethodInfo methodInfo10 = AccessTools.Method(typeof(GameCameraPatch), "PostfixGetCameraPosition", (Type[])null, (Type[])null);
					harmony.Patch((MethodBase)methodInfo8, new HarmonyMethod(methodInfo9), new HarmonyMethod(methodInfo10), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Debug("Vanilla first-person camera mode patched.");
				}
				Type type2 = AccessTools.TypeByName("Player");
				MethodInfo methodInfo11 = type2?.GetMethod("Dodge", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Vector3) }, null);
				if (methodInfo11 != null)
				{
					MethodInfo methodInfo12 = AccessTools.Method(typeof(GameCameraPatch), "PrefixPlayerDodge", (Type[])null, (Type[])null);
					harmony.Patch((MethodBase)methodInfo11, new HarmonyMethod(methodInfo12), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Debug("First-person roll direction patched.");
				}
				MethodInfo methodInfo13 = type2?.GetMethod("SetMouseLook", bindingAttr, null, new Type[1] { typeof(Vector2) }, null);
				if (methodInfo13 != null)
				{
					MethodInfo methodInfo14 = AccessTools.Method(typeof(GameCameraPatch), "PrefixPlayerSetMouseLook", (Type[])null, (Type[])null);
					harmony.Patch((MethodBase)methodInfo13, new HarmonyMethod(methodInfo14), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Debug("Alt free-look movement heading patched before Player.SetMouseLook.");
				}
				MethodInfo method2 = type.GetMethod("RayTestPoint", bindingAttr, null, new Type[4]
				{
					typeof(Vector3),
					typeof(Vector3),
					typeof(float),
					typeof(Vector3).MakeByRefType()
				}, null);
				if (method2 != null)
				{
					MethodInfo methodInfo15 = AccessTools.Method(typeof(GameCameraPatch), "PrefixRayTestPoint4", (Type[])null, (Type[])null);
					harmony.Patch((MethodBase)method2, new HarmonyMethod(methodInfo15), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Debug("Camera collision (RayTestPoint) patched.");
				}
				MethodInfo method3 = type.GetMethod("RayTestPoint", bindingAttr, null, new Type[5]
				{
					typeof(Vector3),
					typeof(Vector3),
					typeof(Vector3),
					typeof(float),
					typeof(float).MakeByRefType()
				}, null);
				if (method3 != null)
				{
					MethodInfo methodInfo16 = AccessTools.Method(typeof(GameCameraPatch), "PrefixRayTestPoint5", (Type[])null, (Type[])null);
					harmony.Patch((MethodBase)method3, new HarmonyMethod(methodInfo16), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo method4 = type.GetMethod("RayTest", bindingAttr, null, new Type[3]
				{
					typeof(Vector3),
					typeof(Vector3),
					typeof(float)
				}, null);
				if (method4 != null)
				{
					MethodInfo methodInfo17 = AccessTools.Method(typeof(GameCameraPatch), "PrefixRayTest", (Type[])null, (Type[])null);
					harmony.Patch((MethodBase)method4, new HarmonyMethod(methodInfo17), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			catch (Exception exception)
			{
				Report(exception);
			}
		}

		private void PatchEnvironmentManager()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			try
			{
				Type type = AccessTools.TypeByName("EnvMan");
				if (type == null)
				{
					Debug("EnvMan was not found; brightness controls are unavailable.");
					return;
				}
				MethodInfo methodInfo = FindEnvironmentMethod(type, "SetEnv", 6);
				if (methodInfo != null)
				{
					MethodInfo methodInfo2 = AccessTools.Method(typeof(EnvironmentPatch), "Postfix", (Type[])null, (Type[])null);
					harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Debug("Client brightness patched at " + methodInfo?.ToString() + ".");
				}
				else
				{
					Debug("EnvMan.SetEnv was not found; brightness controls are unavailable.");
				}
			}
			catch (Exception exception)
			{
				Report(exception);
			}
		}

		private static MethodInfo FindEnvironmentMethod(Type type, string name, int parameterCount)
		{
			if (type == null)
			{
				return null;
			}
			MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name == name && methodInfo.GetParameters().Length == parameterCount)
				{
					return methodInfo;
				}
			}
			return null;
		}

		internal static void Report(Exception exception)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogError((object)exception);
			}
		}

		internal static void Debug(string message)
		{
			if ((Object)(object)Instance != (Object)null && DebugLogging != null && DebugLogging.Value)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[Immersive Camera Enhanced] " + message));
			}
		}

		private void OnDestroy()
		{
			if (harmony != null)
			{
				try
				{
					harmony.UnpatchSelf();
				}
				catch (Exception exception)
				{
					Report(exception);
				}
				harmony = null;
			}
			if (Object.op_Implicit((Object)(object)Controller))
			{
				Object.Destroy((Object)(object)((Component)Controller).gameObject);
			}
			Controller = null;
			Instance = null;
		}
	}
	internal static class EnvironmentPatch
	{
		[HarmonyPriority(0)]
		public static void Postfix(object __instance, object __0)
		{
			try
			{
				if (Plugin.ModEnabled && (Object)(object)Plugin.Controller != (Object)null)
				{
					Plugin.Controller.OnEnvironmentUpdated(__instance, __0);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	internal static class GameCameraPatch
	{
		private static readonly RaycastHit[] hitBuffer = (RaycastHit[])(object)new RaycastHit[96];

		public static IEnumerable<CodeInstruction> TranspileUpdateCamera(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo scrollReplacement = AccessTools.Method(typeof(GameCameraPatch), "GetCameraScrollWheel", (Type[])null, (Type[])null);
			MethodInfo mouseReplacement = AccessTools.Method(typeof(GameCameraPatch), "GetCameraMouseDelta", (Type[])null, (Type[])null);
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.operand is MethodInfo methodInfo && methodInfo.DeclaringType?.Name == "ZInput" && methodInfo.Name == "GetMouseScrollWheel")
				{
					instruction.opcode = OpCodes.Call;
					instruction.operand = scrollReplacement;
				}
				else if (instruction.operand is MethodInfo methodInfo2 && methodInfo2.DeclaringType?.Name == "ZInput" && methodInfo2.Name == "GetMouseDelta")
				{
					instruction.opcode = OpCodes.Call;
					instruction.operand = mouseReplacement;
				}
				yield return instruction;
			}
		}

		public static IEnumerable<CodeInstruction> TranspilePlayerControllerMouseInput(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo mouseReplacement = AccessTools.Method(typeof(GameCameraPatch), "GetCameraMouseDelta", (Type[])null, (Type[])null);
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.operand is MethodInfo methodInfo && methodInfo.DeclaringType?.Name == "ZInput" && methodInfo.Name == "GetMouseDelta")
				{
					instruction.opcode = OpCodes.Call;
					instruction.operand = mouseReplacement;
				}
				yield return instruction;
			}
		}

		public static float GetCameraScrollWheel()
		{
			if (!((Object)(object)Plugin.Controller != (Object)null))
			{
				return 0f;
			}
			return Plugin.Controller.ReadCameraScrollForVanilla();
		}

		public static Vector2 GetCameraMouseDelta()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Plugin.Controller != (Object)null))
			{
				return Vector2.zero;
			}
			return Plugin.Controller.ReadCameraMouseDeltaForVanilla();
		}

		public static void PrefixUpdateCamera(object __instance)
		{
			try
			{
				if ((Object)(object)Plugin.Controller != (Object)null)
				{
					Plugin.Controller.PrepareGameCameraUpdate(__instance);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		[HarmonyPriority(0)]
		public static void PostfixUpdateCamera(object __instance)
		{
			try
			{
				if ((Object)(object)Plugin.Controller != (Object)null)
				{
					Plugin.Controller.ApplyConfiguredCameraLimits(__instance);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		[HarmonyPriority(0)]
		public static void PrefixGetCameraPosition(object __instance)
		{
			try
			{
				if ((Object)(object)Plugin.Controller != (Object)null)
				{
					Plugin.Controller.ApplyConfiguredCameraLimits(__instance);
					Plugin.Controller.ApplyFirstPersonCameraMode(__instance);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		[HarmonyPriority(0)]
		public static void PostfixGetCameraPosition(object __instance, ref Vector3 __1, ref Quaternion __2)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)Plugin.Controller != (Object)null)
				{
					Plugin.Controller.ApplyAdvancedCamera(__instance, ref __1, __2);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		public static void PrefixPlayerDodge(object __instance, ref Vector3 __0)
		{
			try
			{
				if ((Object)(object)Plugin.Controller != (Object)null)
				{
					Plugin.Controller.ApplyFirstPersonRollDirection(__instance, ref __0);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		public static void PrefixPlayerSetMouseLook(object __instance, ref Vector2 __0)
		{
			try
			{
				if ((Object)(object)Plugin.Controller != (Object)null)
				{
					Plugin.Controller.SuppressPlayerLookDuringFreeLook(__instance, ref __0);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		[HarmonyPriority(0)]
		public static void Postfix(object __instance)
		{
			try
			{
				if (Plugin.ModEnabled && (Object)(object)Plugin.Controller != (Object)null)
				{
					Plugin.Controller.OnGameCameraUpdated(__instance);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		public static bool PrefixRayTestPoint4(object __instance, Vector3 __0, Vector3 __1, float __2, ref Vector3 __3, ref bool __result)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (!IsFilteringEnabled())
			{
				return true;
			}
			try
			{
				float distance;
				bool flag = FindNearestSolid(__0, __1, __2, raycast: false, out distance);
				if (!flag)
				{
					flag = FindNearestSolid(__0, __1, __2, raycast: true, out distance);
				}
				if (flag)
				{
					__3 = __0 + ((Vector3)(ref __1)).normalized * Mathf.Max(0f, distance - 0.05f);
				}
				else
				{
					__3 = Vector3.zero;
				}
				__result = flag;
				return false;
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
				return true;
			}
		}

		public static bool PrefixRayTestPoint5(object __instance, Vector3 __0, Vector3 __1, Vector3 __2, float __3, ref float __4, ref bool __result)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!IsFilteringEnabled())
			{
				return true;
			}
			try
			{
				float distance;
				bool flag = FindNearestSolid(__0, __2, __3, raycast: false, out distance);
				if (!flag)
				{
					flag = FindNearestSolid(__1, __2, __3, raycast: false, out distance);
				}
				if (!flag)
				{
					flag = FindNearestSolid(__1, __2, __3, raycast: true, out distance);
				}
				__4 = (flag ? Mathf.Max(0f, distance) : __3);
				__result = flag;
				return false;
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
				return true;
			}
		}

		public static bool PrefixRayTest(object __instance, Vector3 __0, Vector3 __1, float __2, ref float __result)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (!IsFilteringEnabled())
			{
				return true;
			}
			try
			{
				float distance;
				bool flag = FindNearestSolid(__0, __1, __2, raycast: false, out distance);
				if (!flag)
				{
					flag = FindNearestSolid(__0, __1, __2, raycast: true, out distance);
				}
				__result = (flag ? distance : __2);
				return false;
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
				return true;
			}
		}

		private static bool IsFilteringEnabled()
		{
			bool flag = Plugin.IgnoreVegetationCollision != null && Plugin.IgnoreVegetationCollision.Value;
			bool flag2 = Plugin.IgnoreHousePillarCollision != null && Plugin.IgnoreHousePillarCollision.Value;
			bool flag3 = Plugin.IgnoreHouseLightCollision != null && Plugin.IgnoreHouseLightCollision.Value;
			bool flag4 = Plugin.IgnoreEntityCollision != null && Plugin.IgnoreEntityCollision.Value;
			bool flag5 = Plugin.KeepFoundationFloorRoofCollision != null && Plugin.KeepFoundationFloorRoofCollision.Value;
			if (Plugin.ModEnabled && (flag || flag2 || flag3 || flag4 || flag5) && (Object)(object)Plugin.Controller != (Object)null)
			{
				return Plugin.Controller.HasLocalPlayer();
			}
			return false;
		}

		private static bool FindNearestSolid(Vector3 origin, Vector3 direction, float maxDistance, bool raycast, out float distance, bool ignoreHorizontalStructuralSurfaces = false)
		{
			//IL_0025: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			distance = maxDistance;
			if (maxDistance <= 0.001f)
			{
				return false;
			}
			Vector3 val = ((((Vector3)(ref direction)).sqrMagnitude > 0.0001f) ? ((Vector3)(ref direction)).normalized : Vector3.forward);
			int num = ((Plugin.CameraCollisionMask != null) ? Plugin.CameraCollisionMask.Value : (-1));
			int num2 = (raycast ? Physics.RaycastNonAlloc(origin, val, hitBuffer, maxDistance, num, (QueryTriggerInteraction)1) : Physics.SphereCastNonAlloc(origin, 0.22f, val, hitBuffer, maxDistance, num, (QueryTriggerInteraction)1));
			bool flag = false;
			for (int i = 0; i < num2; i++)
			{
				RaycastHit hit = hitBuffer[i];
				Collider collider = ((RaycastHit)(ref hit)).collider;
				if (Object.op_Implicit((Object)(object)collider) && !Plugin.Controller.ShouldIgnoreCameraCollider(collider) && (!ignoreHorizontalStructuralSurfaces || !(Mathf.Abs(((RaycastHit)(ref hit)).normal.y) > 0.7f) || !Plugin.Controller.IsHorizontalStructuralSurface(collider)))
				{
					float cameraCollisionDistance = Plugin.Controller.GetCameraCollisionDistance(hit);
					if (!flag || cameraCollisionDistance < distance)
					{
						distance = cameraCollisionDistance;
						flag = true;
					}
				}
			}
			return flag;
		}

		internal static bool TryFindNearestSolid(Vector3 origin, Vector3 direction, float maxDistance, out float distance)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return TryFindNearestSolid(origin, direction, maxDistance, ignoreHorizontalStructuralSurfaces: false, out distance);
		}

		internal static bool TryFindNearestSolid(Vector3 origin, Vector3 direction, float maxDistance, bool ignoreHorizontalStructuralSurfaces, out float distance)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (FindNearestSolid(origin, direction, maxDistance, raycast: false, out distance, ignoreHorizontalStructuralSurfaces))
			{
				return true;
			}
			return FindNearestSolid(origin, direction, maxDistance, raycast: true, out distance, ignoreHorizontalStructuralSurfaces);
		}
	}
	internal sealed class CameraCullController : MonoBehaviour
	{
		private static readonly string[] stoneTokens = new string[11]
		{
			"rock", "stone", "boulder", "ore", "oredeposit", "flint", "obsidian", "silvervein", "copperdeposit", "tin",
			"crystal"
		};

		private static readonly string[] smallVegetationTokens = new string[21]
		{
			"grass", "bush", "shrub", "fern", "reed", "heath", "heather", "thistle", "dandelion", "berry",
			"raspberry", "blueberry", "cloudberry", "mushroom", "plant", "vine", "flax", "barley", "carrot", "turnip",
			"onion"
		};

		private static readonly string[] largeTreeTokens = new string[18]
		{
			"tree", "beech", "birch", "oak", "pine", "fir", "ash", "juniper", "yggdrasil", "treelog",
			"treebase", "trunk", "branch", "stubbe", "treestump", "tree_stump", "ashlandstump", "swamptree"
		};

		private static readonly string[] treeRootTokens = new string[12]
		{
			"beech", "birch", "oak", "pine", "fir", "ash", "yggdrasil", "stubbe", "treestump", "tree_stump",
			"ashlandstump", "swamptree"
		};

		private static readonly string[] youngTreeTokens = new string[13]
		{
			"sapling", "seedling", "youngtree", "young_tree", "smalltree", "small_tree", "tree_small", "beech_small", "birch_small", "pine_small",
			"fir_small", "oak_small", "ash_small"
		};

		private static readonly string[] explicitLeafRendererTokens = new string[11]
		{
			"leaf", "leaves", "leafmesh", "leafcard", "leafcluster", "leafclump", "canopy", "treetop", "crown", "needle",
			"needles"
		};

		private static readonly string[] trunkTokens = new string[7] { "trunk", "treelog", "treebase", "stem", "bark", "wood", "branch" };

		private static readonly string[] vegetationTagTokens = new string[3] { "tree", "vegetation", "foliage" };

		private static readonly string[] structureTokens = new string[27]
		{
			"wall", "foundation", "floor", "roof", "ceiling", "beam", "pole", "stake", "fence", "gate",
			"door", "house", "building", "bridge", "ladder", "chest", "bed", "workbench", "portal", "pillar",
			"column", "support", "post", "verticalbeam", "stonecolumn", "stonepillar", "arch"
		};

		private static readonly string[] housePillarTokens = new string[23]
		{
			"pillar", "pole", "support", "woodpole", "corewood", "ironbeam", "beam", "post", "column", "verticalbeam",
			"woodpost", "woodcolumn", "stonepillar", "stonecolumn", "marblecolumn", "blackmarblecolumn", "ironcolumn", "rockpillar", "verticalpost", "verticalsupport",
			"pilar", "coluna", "poste"
		};

		private static readonly string[] explicitPillarTokens = new string[8] { "pillar", "column", "support", "post", "vertical", "pilar", "coluna", "poste" };

		private static readonly string[] stoneArchTokens = new string[10] { "stone_arch", "stonearch", "arch_stone", "archstone", "marble_arch", "marblearch", "blackmarble_arch", "blackmarblearch", "grausten_arch", "graustenarch" };

		private static readonly string[] woodStructureTokens = new string[10] { "wood", "finewood", "corewood", "roundlog", "logwood", "ironwood", "woodwall", "woodfloor", "woodroof", "woodceiling" };

		private static readonly string[] cameraPassThroughPropTokens = new string[31]
		{
			"torch", "walltorch", "standingtorch", "lantern", "brazier", "sconce", "candle", "candlestick", "lamp", "fireplace",
			"ironfireplace", "bonfire", "firepit", "hearth", "lightfixture", "walllight", "wall_light", "arandela", "chandelier", "candelabra",
			"piece_table", "table_", "_table", "roundtable", "longtable", "woodtable", "marbletable", "workbench", "artisanstation", "magetable",
			"blackforge"
		};

		private static readonly string[] darkEnvironmentTokens = new string[14]
		{
			"cave", "crypt", "dungeon", "burial", "interior", "mine", "infested", "sunken", "mist", "fog",
			"tomb", "temple", "frostcave", "queen"
		};

		private static readonly string[] foundationFloorRoofTokens = new string[5] { "wall", "foundation", "floor", "ceiling", "roof" };

		private static readonly string[] worldUiTokens = new string[11]
		{
			"nameplate", "name_plate", "healthbar", "health_bar", "worldtext", "world_text", "floatingtext", "floating_text", "overhead", "canvas",
			"hud"
		};

		private readonly Dictionary<Renderer, bool> originalForceRenderingOff = new Dictionary<Renderer, bool>();

		private readonly Dictionary<Renderer, ShadowCastingMode> originalShadowCastingMode = new Dictionary<Renderer, ShadowCastingMode>();

		private readonly Dictionary<Renderer, Mesh> leafOnlyOriginalMeshes = new Dictionary<Renderer, Mesh>();

		private readonly Dictionary<Renderer, Mesh> leafOnlyMeshes = new Dictionary<Renderer, Mesh>();

		private readonly Dictionary<Renderer, Mesh> leafOnlyReusableMeshes = new Dictionary<Renderer, Mesh>();

		private readonly Dictionary<Renderer, Mesh> leafOnlyReusableSources = new Dictionary<Renderer, Mesh>();

		private readonly Dictionary<Renderer, GameObject> leafOnlyShadowObjects = new Dictionary<Renderer, GameObject>();

		private readonly Dictionary<Mesh, Vector3[]> meshVertexCache = new Dictionary<Mesh, Vector3[]>();

		private readonly Dictionary<Mesh, int[]> meshTriangleCache = new Dictionary<Mesh, int[]>();

		private readonly Dictionary<Collider, Renderer[]> colliderRendererCache = new Dictionary<Collider, Renderer[]>();

		private readonly Dictionary<Transform, Renderer[]> treeRendererCache = new Dictionary<Transform, Renderer[]>();

		private readonly Dictionary<Transform, Transform> vegetationRootCache = new Dictionary<Transform, Transform>();

		private readonly Dictionary<Transform, bool> vegetationRootCameraSideState = new Dictionary<Transform, bool>();

		private readonly Dictionary<Renderer, bool> mobRendererClassification = new Dictionary<Renderer, bool>();

		private readonly Dictionary<Transform, string> hierarchyNameCache = new Dictionary<Transform, string>();

		private readonly Dictionary<Collider, bool> foundationWoodClassification = new Dictionary<Collider, bool>();

		private readonly HashSet<Renderer> shapeOccluders = new HashSet<Renderer>();

		private readonly HashSet<Renderer> nextShapeOccluders = new HashSet<Renderer>();

		private readonly List<Renderer> shapeOccluderScratch = new List<Renderer>(128);

		private readonly Dictionary<Renderer, byte> shapeOccluderExitMisses = new Dictionary<Renderer, byte>();

		private readonly Dictionary<Renderer, float> shapeOccluderOutsideSince = new Dictionary<Renderer, float>();

		private readonly Dictionary<Renderer, bool> vegetationClassification = new Dictionary<Renderer, bool>();

		private readonly Dictionary<Renderer, bool> smallVegetationClassification = new Dictionary<Renderer, bool>();

		private readonly Dictionary<Collider, bool> vegetationColliderClassification = new Dictionary<Collider, bool>();

		private readonly Dictionary<Collider, bool> entityColliderClassification = new Dictionary<Collider, bool>();

		private readonly Dictionary<Collider, bool> structureColliderClassification = new Dictionary<Collider, bool>();

		private readonly Dictionary<Collider, bool> foundationFloorRoofColliderClassification = new Dictionary<Collider, bool>();

		private readonly Dictionary<Collider, bool> housePillarColliderClassification = new Dictionary<Collider, bool>();

		private readonly Dictionary<Transform, CapsuleCollider> youngTreeProbeColliders = new Dictionary<Transform, CapsuleCollider>();

		private readonly Dictionary<Collider, Transform> youngTreeProbeOwners = new Dictionary<Collider, Transform>();

		private readonly Dictionary<Transform, Bounds> youngTreeProbeBounds = new Dictionary<Transform, Bounds>();

		private readonly HashSet<Transform> youngTreeProbeDesired = new HashSet<Transform>();

		private readonly List<Transform> youngTreeProbeScratch = new List<Transform>(64);

		private readonly Dictionary<Vector2Int, List<Renderer>> vegetationSpatialGrid = new Dictionary<Vector2Int, List<Renderer>>();

		private readonly HashSet<Renderer> spatialQueryCandidates = new HashSet<Renderer>();

		private readonly HashSet<Collider> shapeColliders = new HashSet<Collider>();

		private readonly Collider[] shapeColliderBuffer = (Collider[])(object)new Collider[512];

		private readonly Collider[] youngTreeColliderBuffer = (Collider[])(object)new Collider[512];

		private GameObject occlusionCylinderObject;

		private CapsuleCollider occlusionCylinderCollider;

		private GameObject[] occlusionCylinderSlices;

		private SphereCollider[] occlusionCylinderSliceColliders;

		private Material debugCylinderMaterial;

		private Vector3 debugCylinderStart;

		private Vector3 debugCylinderEnd;

		private float debugCylinderCameraT;

		private float debugCylinderCameraRadius;

		private float debugCylinderRearRadius;

		private float debugCylinderGrowthExponent;

		private bool debugCylinderReady;

		private Vector3 mainVolumeStart;

		private Vector3 mainVolumeEnd;

		private Vector3 mainVolumeCharacterCenter;

		private float mainVolumeCameraT;

		private float mainVolumeCameraRadius;

		private float mainVolumeRearRadius;

		private float mainVolumeGrowthExponent;

		private bool mainVolumeReady;

		private Vector3 previousPlayerPosition;

		private bool previousPlayerPositionReady;

		private float towardCameraMovementStartedAt = -1f;

		private int spatialQueryCursor;

		private bool temporaryLeavesOnlyActive;

		private int towardCameraMovementFrames;

		private bool modResetApplied;

		private Renderer[] vegetationRenderers = (Renderer[])(object)new Renderer[0];

		private Renderer[] housePillarRenderers = (Renderer[])(object)new Renderer[0];

		private Coroutine scanRoutine;

		private const float VegetationGridCellSize = 16f;

		private Camera cachedCamera;

		private Type playerType;

		private MemberInfo localPlayerMember;

		private MemberInfo playerBoatMember;

		private MethodInfo playerBoatMethod;

		private MethodInfo playerIsCrouchingMethod;

		private MemberInfo playerCrouchToggledMember;

		private MemberInfo playerMoveDirMember;

		private MemberInfo playerCurrentVelocityMember;

		private MemberInfo playerRightItemMember;

		private MemberInfo playerLeftItemMember;

		private Type cachedItemDataType;

		private MemberInfo itemSharedMember;

		private Type cachedItemSharedType;

		private MemberInfo itemNameMember;

		private MemberInfo placementGhostMember;

		private Transform activePlacementGhost;

		private int placementGhostRefreshFrame = -1;

		private Type menuType;

		private MemberInfo menuInstanceMember;

		private MemberInfo menuRootMember;

		private MethodInfo menuIsVisibleMethod;

		private string tokenSource;

		private string protectedTokenSource;

		private string[] vegetationTokens = new string[0];

		private string[] protectedTokens = new string[0];

		private readonly HashSet<int> unknownCameraColliders = new HashSet<int>();

		private const float DefaultShapeQueryInterval = 0.6f;

		private const float YoungTreeProbeHeight = 6f;

		private const float YoungTreeProbeRadiusMultiplier = 3f;

		private const float YoungTreeProbeMaxRadius = 4f;

		private const float OccluderExitPadding = 0.2f;

		private const float VegetationSideEnterThreshold = -0.25f;

		private const float VegetationSideExitThreshold = -0.8f;

		private const int MaxRendererProbesPerQuery = 0;

		private const int MaxMeshCacheEntries = 256;

		private const float VerboseStatusInterval = 15f;

		private const int MaxYoungTreeProbes = 96;

		private const float YoungTreeProbeRange = 48f;

		private static readonly string[] advancedHeightIgnoredObjectTokens = new string[19]
		{
			"chest", "table", "workbench", "portal", "bed", "forge", "station", "torch", "sconce", "lantern",
			"brazier", "fireplace", "hearth", "candle", "lamp", "lightfixture", "arandela", "chandelier", "candelabra"
		};

		private MemberInfo gameCameraCameraMember;

		private FieldInfo gameCameraDistanceField;

		private FieldInfo gameCameraMinDistanceField;

		private FieldInfo gameCameraMaxDistanceField;

		private FieldInfo gameCameraMaxDistanceBoatField;

		private FieldInfo gameCameraZoomSensitivityField;

		private MethodInfo gameCameraGetOffsetedEyePosMethod;

		private bool gameCameraReflectionReady;

		private object firstPersonCameraInstance;

		private float savedThirdPersonDistance = 4f;

		private bool firstPersonDistanceApplied;

		private bool firstPersonScrollRequested;

		private int firstPersonScrollFrame = -1;

		private Camera firstPersonEffectsCamera;

		private Vector3 firstPersonSwayPreviousPosition;

		private bool firstPersonSwayPositionReady;

		private float firstPersonSwayPhase;

		private float firstPersonSwaySpeed;

		private float firstPersonCrouchOffset;

		private Quaternion firstPersonSwayRotation = Quaternion.identity;

		private int firstPersonEffectsFrame = -1;

		private Camera firstPersonFovCamera;

		private float firstPersonOriginalFov = 65f;

		private bool firstPersonFovApplied;

		private float cameraZoomMagnification = 1f;

		private float cameraZoomTargetMagnification = 1f;

		private bool cameraZoomActive;

		private bool cameraZoomWasHeld;

		private Vector2 cameraMouseDeltaSmoothed;

		private int cameraMouseDeltaSmoothFrame = -1;

		private int cameraZoomScrollFrame = -1;

		private int zoomInputFrame = -1;

		private bool zoomInputHeldCached;

		private Camera cameraZoomFovCamera;

		private float cameraZoomOriginalFov;

		private float cameraZoomAppliedFov;

		private int cameraZoomFovFrame = -1;

		private object cameraDistanceStateInstance;

		private float cameraDistanceSmoothed;

		private float cameraDistanceTarget;

		private bool cameraDistanceStateReady;

		private bool freeLookActive;

		private bool freeLookReturning;

		private float freeLookCharacterYaw;

		private float freeLookYaw;

		private float freeLookPitch;

		private int freeLookInputFrame = -1;

		private Quaternion freeLookInitialRotation = Quaternion.identity;

		private bool freeLookInitialTransformReady;

		private readonly RaycastHit[] advancedCameraHits = (RaycastHit[])(object)new RaycastHit[64];

		private bool advancedCeilingActive;

		private bool advancedCeilingCheckValid;

		private float nextAdvancedCeilingCheckAt;

		private MemberInfo playerEyeMember;

		private bool cachedBoatState;

		private float nextBoatStateCheck;

		private MethodInfo zInputGetMouseScrollWheelMethod;

		private Func<float> zInputGetMouseScrollWheelDelegate;

		private bool zInputScrollLookupAttempted;

		private MethodInfo zInputGetMouseDeltaMethod;

		private Func<Vector2> zInputGetMouseDeltaDelegate;

		private bool zInputMouseDeltaLookupAttempted;

		private MethodInfo unityInputGetKeyMethod;

		private Func<KeyCode, bool> unityInputGetKeyDelegate;

		private bool unityInputGetKeyLookupAttempted;

		private MethodInfo zInputGetKeyMethod;

		private Func<KeyCode, bool> zInputGetKeyDelegate;

		private bool zInputGetKeyLookupAttempted;

		private float nextShapeQueryAt;

		private bool visualModeInitialized;

		private bool lastLeavesOnly;

		private bool lastCullHousePillars;

		private bool lastPreserveVegetationShadows;

		private float nextVerboseStatusAt;

		private int unknownCameraColliderLogCount;

		private int verboseHideTransitions;

		private int verboseRestoreTransitions;

		private float lastShapeQueryMs;

		private float peakShapeQueryMs;

		private long lastShapeQueryTicks;

		private long peakShapeQueryTicks;

		private float lastVolumeUpdateMs;

		private float peakVolumeUpdateMs;

		private long lastVolumeUpdateTicks;

		private long peakVolumeUpdateTicks;

		private long lastManagedMemoryBytes;

		private long peakManagedMemoryBytes;

		private long lastUnityAllocatedBytes;

		private long peakUnityAllocatedBytes;

		private long lastWorkingSetBytes;

		private float lastCpuPercent;

		private int lastProcessThreadCount;

		private long cpuSampleTimestamp;

		private TimeSpan cpuSampleProcessTime;

		private int lastGc0Collections;

		private int lastGc1Collections;

		private int lastGc2Collections;

		private float peakFrameMs;

		private int framesOver16Ms;

		private int framesOver33Ms;

		private int framesOver100Ms;

		private bool environmentReflectionReady;

		private FieldInfo currentEnvironmentField;

		private FieldInfo environmentNameField;

		private FieldInfo environmentAlwaysDarkField;

		private FieldInfo environmentDirectionalLightField;

		private FieldInfo environmentAmbientShaderIdField;

		private FieldInfo environmentSunFogColorField;

		private FieldInfo environmentSunFogShaderIdField;

		private MethodInfo environmentIsNightMethod;

		private MethodInfo environmentIsDayMethod;

		private static float CurrentShapeQueryInterval
		{
			get
			{
				if (Plugin.CylinderCheckInterval == null)
				{
					return 0.6f;
				}
				return Mathf.Clamp(Plugin.CylinderCheckInterval.Value, 0.05f, 2f);
			}
		}

		private static float CurrentCylinderRestoreDelay
		{
			get
			{
				if (Plugin.CylinderRestoreDelay == null)
				{
					return 0.6f;
				}
				return Mathf.Clamp(Plugin.CylinderRestoreDelay.Value, 0f, 2f);
			}
		}

		private static float CurrentMovementLeavesOnlyActivationDelay
		{
			get
			{
				if (Plugin.MovementLeavesOnlyActivationDelay == null)
				{
					return 0.5f;
				}
				return Mathf.Clamp(Plugin.MovementLeavesOnlyActivationDelay.Value, 0.1f, 5f);
			}
		}

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Expected O, but got Unknown
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
			Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnCameraPreCull));
			SceneManager.sceneLoaded += OnSceneLoaded;
			SceneManager.sceneUnloaded += OnSceneUnloaded;
			occlusionCylinderObject = new GameObject("ImmersiveCameraEnhancedOcclusionCylinder");
			occlusionCylinderObject.transform.SetParent(((Component)this).transform, false);
			occlusionCylinderObject.layer = 2;
			occlusionCylinderCollider = occlusionCylinderObject.AddComponent<CapsuleCollider>();
			occlusionCylinderCollider.direction = 1;
			((Collider)occlusionCylinderCollider).isTrigger = true;
			((Collider)occlusionCylinderCollider).enabled = false;
			occlusionCylinderSlices = (GameObject[])(object)new GameObject[8];
			occlusionCylinderSliceColliders = (SphereCollider[])(object)new SphereCollider[8];
			for (int i = 0; i < 8; i++)
			{
				GameObject val = new GameObject("ImmersiveCameraEnhancedOcclusionSlice" + i);
				val.transform.SetParent(occlusionCylinderObject.transform, false);
				val.layer = 2;
				SphereCollider val2 = val.AddComponent<SphereCollider>();
				((Collider)val2).isTrigger = true;
				((Collider)val2).enabled = false;
				occlusionCylinderSlices[i] = val;
				occlusionCylinderSliceColliders[i] = val2;
			}
			Shader val3 = Shader.Find("Hidden/Internal-Colored");
			if (Object.op_Implicit((Object)(object)val3))
			{
				debugCylinderMaterial = new Material(val3)
				{
					hideFlags = (HideFlags)61
				};
				debugCylinderMaterial.SetInt("_ZWrite", 0);
				debugCylinderMaterial.SetInt("_ZTest", 8);
				debugCylinderMaterial.SetInt("_SrcBlend", 5);
				debugCylinderMaterial.SetInt("_DstBlend", 10);
				debugCylinderMaterial.SetInt("_Cull", 0);
			}
		}

		private void OnDestroy()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(OnCameraPreCull));
			SceneManager.sceneLoaded -= OnSceneLoaded;
			SceneManager.sceneUnloaded -= OnSceneUnloaded;
			ResetWorldState();
			if (Object.op_Implicit((Object)(object)occlusionCylinderObject))
			{
				Object.Destroy((Object)(object)occlusionCylinderObject);
			}
			if (Object.op_Implicit((Object)(object)debugCylinderMaterial))
			{
				Object.Destroy((Object)(object)debugCylinderMaterial);
			}
			occlusionCylinderCollider = null;
			occlusionCylinderObject = null;
			occlusionCylinderSlices = null;
			occlusionCylinderSliceColliders = null;
			debugCylinderMaterial = null;
			debugCylinderReady = false;
		}

		private void OnRenderObject()
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.ModEnabled || !Plugin.ShowOcclusionCylinder.Value || !Object.op_Implicit((Object)(object)debugCylinderMaterial))
			{
				return;
			}
			Camera current = Camera.current;
			if (IsGameplayCamera(current))
			{
				debugCylinderMaterial.SetPass(0);
				GL.PushMatrix();
				GL.Begin(1);
				float num = ((Plugin.CylinderDebugOpacity != null) ? Mathf.Clamp01(Plugin.CylinderDebugOpacity.Value) : 0.2f);
				GL.Color(new Color(0.1f, 1f, 0.25f, num));
				if (debugCylinderReady && Object.op_Implicit((Object)(object)occlusionCylinderCollider) && ((Collider)occlusionCylinderCollider).enabled)
				{
					DrawDebugCone(debugCylinderStart, debugCylinderEnd, debugCylinderCameraT, debugCylinderCameraRadius, debugCylinderRearRadius, debugCylinderGrowthExponent, ((Component)current).transform.right);
				}
				GL.End();
				GL.PopMatrix();
			}
		}

		private static float RadiusAtNormalizedDistance(float t, float cameraT, float cameraRadius, float rearRadius, float growthExponent, float totalLength)
		{
			t = Mathf.Clamp01(t);
			cameraT = Mathf.Clamp(cameraT, 0.0001f, 0.9999f);
			float num = ((Plugin.CylinderExponentInfluencePercent != null) ? Mathf.Clamp01(Plugin.CylinderExponentInfluencePercent.Value / 100f) : 1f);
			float num2 = Mathf.Lerp(1f, Mathf.Max(1f, growthExponent), num);
			if (t <= cameraT)
			{
				float normalizedDistance = t / cameraT;
				normalizedDistance = QuantizeProfileDistance(normalizedDistance, totalLength * cameraT);
				return cameraRadius * Mathf.Pow(normalizedDistance, num2);
			}
			float normalizedDistance2 = (t - cameraT) / (1f - cameraT);
			normalizedDistance2 = QuantizeProfileDistance(normalizedDistance2, totalLength * (1f - cameraT));
			return Mathf.Lerp(cameraRadius, rearRadius, Mathf.Pow(normalizedDistance2, num2));
		}

		private static float QuantizeProfileDistance(float normalizedDistance, float segmentLength)
		{
			normalizedDistance = Mathf.Clamp01(normalizedDistance);
			if (normalizedDistance >= 0.9999f)
			{
				return 1f;
			}
			float num = ((Plugin.CylinderSlicesPerMeter != null) ? Mathf.Clamp(Plugin.CylinderSlicesPerMeter.Value, 0.5f, 12f) : 2f);
			int num2 = Mathf.Max(1, Mathf.CeilToInt(Mathf.Max(0.01f, segmentLength) * num));
			return Mathf.Floor(normalizedDistance * (float)num2) / (float)num2;
		}

		private static void DrawDebugCone(Vector3 start, Vector3 end, float cameraT, float cameraRadius, float rearRadius, float growthExponent, Vector3 cameraRight)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: 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_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = end - start;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude <= 0.01f)
			{
				return;
			}
			val /= magnitude;
			Vector3 val2 = Vector3.Cross(val, Vector3.up);
			if (((Vector3)(ref val2)).sqrMagnitude <= 0.001f)
			{
				val2 = Vector3.Cross(val, cameraRight);
			}
			((Vector3)(ref val2)).Normalize();
			Vector3 val3 = Vector3.Cross(val, val2);
			Vector3 normalized = ((Vector3)(ref val3)).normalized;
			int num = Mathf.Clamp(Mathf.CeilToInt(magnitude * ((Plugin.CylinderSlicesPerMeter != null) ? Mathf.Clamp(Plugin.CylinderSlicesPerMeter.Value, 0.5f, 12f) : 2f)), 4, 96);
			float num2 = ((Plugin.CylinderSlicesPerMeter != null) ? Mathf.Clamp(Plugin.CylinderSlicesPerMeter.Value, 0.5f, 12f) : 2f);
			int num3 = Mathf.Clamp(Mathf.CeilToInt(magnitude * num2), 8, 64);
			for (int i = 0; i < num; i++)
			{
				float num4 = (float)i / (float)num;
				float num5 = (float)(i + 1) / (float)num;
				Vector3 val4 = start + val * (magnitude * num4);
				Vector3 val5 = start + val * (magnitude * num5);
				float num6 = RadiusAtNormalizedDistance(num4, cameraT, cameraRadius, rearRadius, growthExponent, magnitude);
				float num7 = RadiusAtNormalizedDistance(num5, cameraT, cameraRadius, rearRadius, growthExponent, magnitude);
				for (int j = 0; j < num3; j++)
				{
					float num8 = MathF.PI * 2f * (float)j / (float)num3;
					float num9 = MathF.PI * 2f * (float)(j + 1) / (float)num3;
					Vector3 val6 = val2 * Mathf.Cos(num8) + normalized * Mathf.Sin(num8);
					Vector3 val7 = val2 * Mathf.Cos(num9) + normalized * Mathf.Sin(num9);
					GL.Vertex(val4 + FlattenDebugOffset(val6 * num6, num6, val));
					GL.Vertex(val4 + FlattenDebugOffset(val7 * num6, num6, val));
					GL.Vertex(val4 + FlattenDebugOffset(val6 * num6, num6, val));
					GL.Vertex(val5 + FlattenDebugOffset(val6 * num7, num7, val));
				}
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			RestoreFirstPersonCamera();
			ResetWorldState();
			cachedCamera = null;
			gameCameraReflectionReady = false;
			gameCameraCameraMember = null;
			gameCameraDistanceField = null;
			gameCameraMinDistanceField = null;
			gameCameraMaxDistanceField = null;
			gameCameraMaxDistanceBoatField = null;
			gameCameraZoomSensitivityField = null;
			gameCameraGetOffsetedEyePosMethod = null;
			firstPersonCameraInstance = null;
			firstPersonDistanceApplied = false;
			firstPersonScrollRequested = false;
			firstPersonScrollFrame = -1;
			cachedBoatState = false;
			nextBoatStateCheck = 0f;
		}

		private void OnSceneUnloaded(Scene scene)
		{
			ResetWorldState();
			cachedCamera = null;
		}

		private void Update()
		{
			try
			{
				if (!Plugin.ModEnabled)
				{
					if (!modResetApplied)
					{
						ResetWorldState();
						modResetApplied = true;
					}
					return;
				}
				modResetApplied = false;
				RecordFramePerformance();
				if (!TryGetLocalPlayer(out var player))
				{
					ResetWorldState();
					return;
				}
				ApplyLiveFirstPersonSettings();
				if (IsPauseMenuVisible())
				{
					ClearShapeOccluders();
					return;
				}
				Camera gameplayCamera = GetGameplayCamera();
				if (!Object.op_Implicit((Object)(object)gameplayCamera))
				{
					ResetWorldState();
					return;
				}
				if (firstPersonDistanceApplied)
				{
					ClearShapeOccluders();
					return;
				}
				UpdateMovementLeavesOnly(player, gameplayCamera);
				SyncVisualModeState();
				UpdateCameraOcclusionVolumesTimed(gameplayCamera, player);
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		private void SyncVisualModeState()
		{
			bool flag = UsesLeavesOnly();
			bool flag2 = ShouldCullHousePillars();
			bool flag3 = Plugin.PreserveVegetationShadows != null && Plugin.PreserveVegetationShadows.Value;
			if (!visualModeInitialized)
			{
				visualModeInitialized = true;
				lastLeavesOnly = flag;
				lastCullHousePillars = flag2;
				lastPreserveVegetationShadows = flag3;
			}
			else if (flag != lastLeavesOnly || flag2 != lastCullHousePillars || flag3 != lastPreserveVegetationShadows)
			{
				if (flag != lastLeavesOnly || flag3 != lastPreserveVegetationShadows)
				{
					ReapplyShapeOcclusionMode();
				}
				lastLeavesOnly = flag;
				lastCullHousePillars = flag2;
				lastPreserveVegetationShadows = flag3;
				nextShapeQueryAt = 0f;
			}
		}

		private IEnumerator DiscoverRenderers()
		{
			yield return null;
			if (!Plugin.ModEnabled || !TryGetLocalPlayer(out var player) || IsPauseMenuVisible())
			{
				scanRoutine = null;
				yield break;
			}
			Renderer[] found;
			try
			{
				found = Object.FindObjectsByType<Renderer>((FindObjectsSortMode)0);
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
				scanRoutine = null;
				yield break;
			}
			List<Renderer> vegetation = new List<Renderer>();
			List<Renderer> housePillars = new List<Renderer>();
			for (int i = 0; i < found.Length; i++)
			{
				if ((i & 0xFF) == 0)
				{
					yield return null;
				}
				Renderer val = found[i];
				if (IsVegetationRenderer(val) && (!IsSmallVegetation(val) || IsYoungTreeRenderer(val)) && IsSafeCameraOccluder(val, player))
				{
					vegetation.Add(val);
				}
				else if (IsHousePillarRenderer(val) && IsSafeCameraOccluder(val, player))
				{
					housePillars.Add(val);
				}
			}
			vegetationRenderers = vegetation.ToArray();
			housePillarRenderers = housePillars.ToArray();
			colliderRendererCache.Clear();
			treeRendererCache.Clear();
			vegetationRootCache.Clear();
			mobRendererClassification.Clear();
			hierarchyNameCache.Clear();
			RebuildYoungTreeProbes(vegetationRenderers, player);
			vegetationClassification.Clear();
			smallVegetationClassification.Clear();
			vegetationSpatialGrid.Clear();
			for (int j = 0; j < vegetationRenderers.Length; j++)
			{
				Renderer val2 = vegetationRenderers[j];
				if (Object.op_Implicit((Object)(object)val2))
				{
					vegetationClassification[val2] = true;
					IndexVegetationRenderer(val2);
				}
			}
			scanRoutine = null;
		}

		private void UpdateCameraOcclusionVolumes(Camera camera, Transform player)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: 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_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: 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_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			HashSet<Renderer> hashSet = nextShapeOccluders;
			hashSet.Clear();
			mainVolumeReady = false;
			if (!Plugin.EnableCylinderOcclusion.Value || !Object.op_Implicit((Object)(object)camera) || !Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)occlusionCylinderCollider))
			{
				if (Object.op_Implicit((Object)(object)occlusionCylinderCollider))
				{
					((Collider)occlusionCylinderCollider).enabled = false;
				}
				DisableCylinderSlices();
				shapeColliders.Clear();
				debugCylinderReady = false;
				ClearShapeOccluders();
				return;
			}
			Vector3 position = ((Component)camera).transform.position;
			Vector3 val = (mainVolumeCharacterCenter = GetPlayerCenter(player));
			Vector3 val2 = position - val;
			float magnitude = ((Vector3)(ref val2)).magnitude;
			if (magnitude <= 0.1f)
			{
				((Collider)occlusionCylinderCollider).enabled = false;
				DisableCylinderSlices();
				shapeColliders.Clear();
				debugCylinderReady = false;
				ClearShapeOccluders();
				return;
			}
			Vector3 val3 = val2 / magnitude;
			float num = Mathf.Clamp(Plugin.ConeCharacterDistance.Value, 0f, 5f);
			Vector3 val4 = val + val3 * num;
			Vector3 val5 = position - val4;
			float magnitude2 = ((Vector3)(ref val5)).magnitude;
			if (magnitude2 <= 0.1f)
			{
				((Collider)occlusionCylinderCollider).enabled = false;
				DisableCylinderSlices();
				shapeColliders.Clear();
				debugCylinderReady = false;
				ClearShapeOccluders();
				return;
			}
			val3 = val5 / magnitude2;
			float num2 = Mathf.Clamp(Plugin.BackCylinderLength.Value, 0.5f, 30f);
			Vector3 val6 = position + val3 * num2;
			Vector3 val7 = val6 - val4;
			float magnitude3 = ((Vector3)(ref val7)).magnitude;
			if (magnitude3 <= 0.1f)
			{
				((Collider)occlusionCylinderCollider).enabled = false;
				DisableCylinderSlices();
				shapeColliders.Clear();
				debugCylinderReady = false;
				ClearShapeOccluders();
				return;
			}
			float screenPercent = Mathf.Clamp(Plugin.CylinderCameraWidthPercent.Value, 0f, 100f);
			float num3 = GetWorldScreenWidth(camera, magnitude2, screenPercent) * 0.5f;
			num3 = Mathf.Clamp(num3, 0.01f, 8f);
			float num4 = Mathf.Clamp(Plugin.ConeRearRadiusMultiplier.Value, 1f, 4f);
			float num5 = Mathf.Clamp(num3 * num4, num3, 16f);
			float growthExponent = Mathf.Clamp(Plugin.ConeGrowthExponent.Value, 1f, 6f);
			float cameraT = Mathf.Clamp01(magnitude2 / magnitude3);
			Vector3 position2 = val4 + val7 * 0.5f;
			occlusionCylinderObject.transform.position = position2;
			occlusionCylinderObject.transform.rotation = Quaternion.FromToRotation(Vector3.up, ((Vector3)(ref val7)).normalized);
			occlusionCylinderCollider.center = Vector3.zero;
			occlusionCylinderCollider.radius = Mathf.Max(0.01f, num5);
			occlusionCylinderCollider.height = magnitude3 + 0.02f;
			((Collider)occlusionCylinderCollider).enabled = true;
			UpdateCylinderSlices(val4, val6, magnitude3, cameraT, num3, num5, growthExponent);
			debugCylinderStart = val4;
			debugCylinderEnd = val6;
			debugCylinderCameraT = cameraT;
			debugCylinderCameraRadius = num3;
			debugCylinderRearRadius = num5;
			debugCylinderGrowthExponent = growthExponent;
			debugCylinderReady = true;
			mainVolumeStart = val4;
			mainVolumeEnd = val6;
			mainVolumeCameraT = cameraT;
			mainVolumeCameraRadius = num3;
			mainVolumeRearRadius = num5;
			mainVolumeGrowthExponent = growthExponent;
			mainVolumeReady = true;
			if (Time.unscaledTime < nextShapeQueryAt)
			{
				return;
			}
			nextShapeQueryAt = Time.unscaledTime + CurrentShapeQueryInterval;
			bool flag = Plugin.DebugLogging != null && Plugin.DebugLogging.Value;
			float num6 = (flag ? Time.realtimeSinceStartup : 0f);
			long num7 = (flag ? Stopwatch.GetTimestamp() : 0);
			shapeColliders.Clear();
			spatialQueryCandidates.Clear();
			CollectVolumeColliders(shapeColliders);
			foreach (Collider shapeCollider in shapeColliders)
			{
				AddColliderRenderers(shapeCollider, player, hashSet);
			}
			ReplaceShapeOccluders(hashSet);
			if (flag)
			{
				long elapsedTicks = Stopwatch.GetTimestamp() - num7;
				RecordShapeQueryMetrics((Time.realtimeSinceStartup - num6) * 1000f, elapsedTicks);
			}
			EmitVerboseStatus(camera);
		}

		private void UpdateCameraOcclusionVolumesTimed(Camera camera, Transform player)
		{
			int num;
			float num2;
			if (Plugin.DebugLogging != null)
			{
				num = (Plugin.DebugLogging.Value ? 1 : 0);
				if (num != 0)
				{
					num2 = Time.realtimeSinceStartup;
					goto IL_0023;
				}
			}
			else
			{
				num = 0;
			}
			num2 = 0f;
			goto IL_0023;
			IL_0023:
			float num3 = num2;
			long num4 = ((num != 0) ? Stopwatch.GetTimestamp() : 0);
			UpdateCameraOcclusionVolumes(camera, player);
			if (num != 0)
			{
				lastVolumeUpdateMs = Mathf.Max(0f, (Time.realtimeSinceStartup - num3) * 1000f);
				lastVolumeUpdateTicks = Math.Max(0L, Stopwatch.GetTimestamp() - num4);
				peakVolumeUpdateMs = Mathf.Max(peakVolumeUpdateMs, lastVolumeUpdateMs);
				peakVolumeUpdateTicks = Math.Max(peakVolumeUpdateTicks, lastVolumeUpdateTicks);
			}
		}

		private void UpdateCylinderSlices(Vector3 start, Vector3 end, float length, float cameraT, float cameraRadius, float rearRadius, float growthExponent)
		{
			//IL_0041: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			if (occlusionCylinderSlices == null || occlusionCylinderSliceColliders == null || !Object.op_Implicit((Object)(object)occlusionCylinderObject))
			{
				return;
			}
			if (Plugin.ShowOcclusionCylinder == null || !Plugin.ShowOcclusionCylinder.Value)
			{
				DisableCylinderSlices();
				return;
			}
			int num = occlusionCylinderSliceColliders.Length;
			Vector3 val = end - start;
			Vector3 val2 = ((length > 0.001f) ? (val / length) : Vector3.up);
			Vector3 position = start + val * 0.5f;
			occlusionCylinderObject.transform.position = position;
			occlusionCylinderObject.transform.rotation = Quaternion.FromToRotation(Vector3.up, val2);
			for (int i = 0; i < num; i++)
			{
				float num2 = ((num <= 1) ? 0f : ((float)i / (float)(num - 1)));
				float num3 = (num2 - 0.5f) * length;
				float num4 = RadiusAtNormalizedDistance(num2, cameraT, cameraRadius, rearRadius, growthExponent, length);
				GameObject val3 = occlusionCylinderSlices[i];
				SphereCollider val4 = occlusionCylinderSliceColliders[i];
				if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val4))
				{
					val3.transform.localPosition = new Vector3(0f, num3, 0f);
					val3.transform.localRotation = Quaternion.identity;
					val4.center = Vector3.zero;
					val4.radius = Mathf.Max(0.01f, num4);
					((Collider)val4).enabled = true;
				}
			}
		}

		private void DisableCylinderSlices()
		{
			if (occlusionCylinderSliceColliders == null)
			{
				return;
			}
			for (int i = 0; i < occlusionCylinderSliceColliders.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)occlusionCylinderSliceColliders[i]))
				{
					((Collider)occlusionCylinderSliceColliders[i]).enabled = false;
				}
			}
		}

		private static float GetWorldScreenWidth(Camera camera, float distance, float screenPercent)
		{
			if (!Object.op_Implicit((Object)(object)camera) || distance <= 0f || screenPercent <= 0f)
			{
				return 0f;
			}
			float num = ((camera.aspect > 0.01f) ? camera.aspect : 1.7777778f);
			float num2 = camera.fieldOfView * (MathF.PI / 180f);
			float num3 = 2f * Mathf.Atan(Mathf.Tan(num2 * 0.5f) * num);
			return 2f * distance * Mathf.Tan(num3 * 0.5f) * (screenPercent / 100f);
		}

		private void CollectVolumeColliders(HashSet<Collider> result)
		{
			//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_00db: Unknown result type (might be due to invalid IL or missing references)
			if (result == null || !mainVolumeReady)
			{
				return;
			}
			float num = Mathf.Max(0.01f, mainVolumeRearRadius);
			int num2 = Physics.OverlapCapsuleNonAlloc(mainVolumeStart, mainVolumeEnd, num, shapeColliderBuffer, Plugin.CameraCollisionMask.Value, (QueryTriggerInteraction)1);
			Collider val = (Object.op_Implicit((Object)(object)occlusionCylinderObject) ? occlusionCylinderObject.GetComponent<Collider>() : null);
			for (int i = 0; i < num2; i++)
			{
				Collider val2 = shapeColliderBuffer[i];
				if (!Object.op_Implicit((Object)(object)val2) || (Object)(object)val2 == (Object)(object)val || (Object.op_Implicit((Object)(object)occlusionCylinderObject) && ((Component)val2).transform.IsChildOf(occlusionCylinderObject.transform)))
				{
					continue;
				}
				bool flag = IsVegetationCollider(val2);
				bool flag2 = false;
				if (!flag)
				{
					if (!ShouldCullHousePillars())
					{
						continue;
					}
					flag2 = IsHousePillarCollider(val2);
					if (!flag2)
					{
						continue;
					}
				}