Decompiled source of CullFactory Beta v1.0.5

CullFactory.dll

Decompiled 7 months ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using CullFactory.Behaviours.CullingMethods;
using CullFactory.Behaviours.Visualization;
using CullFactory.Data;
using CullFactory.Extenders;
using CullFactory.Services;
using DunGen;
using DunGen.Graph;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("CullFactory")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("My first plugin")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+0b44b180540e0a5eb6fca20aef3843dd57d6b01d")]
[assembly: AssemblyProduct("CullFactory")]
[assembly: AssemblyTitle("CullFactory")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 CullFactory
{
	public static class Config
	{
		private static readonly Version DefaultVersion = Version.Parse("0.0.0");

		private static readonly Version FallbackVersion = Version.Parse("0.8.0");

		private static readonly string VersionFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty, "version");

		private static readonly string[] DefaultFlowsToBlockCulling = Array.Empty<string>();

		private static readonly string[] BaseSetOfInteriorsToUseFallbackPortals = new string[2] { "BunkerFlow", "School" };

		private static readonly string[] BaseSetOfInteriorsToSkipFallbackPortals = new string[2] { "CastleFlow", "SewerFlow" };

		private static ConfigEntry<CullingType> Culler;

		private static ConfigEntry<string> InteriorsToBlockCulling;

		private static ConfigEntry<string> InteriorsToForceCulling;

		public static string[] InteriorsWithDisabledCulling = Array.Empty<string>();

		public static ConfigEntry<bool> Logging { get; private set; }

		public static ConfigEntry<float> UpdateFrequency { get; private set; }

		public static ConfigEntry<bool> DisableShadowDistanceFading { get; private set; }

		public static ConfigEntry<string> InteriorsToUseFallbackPortals { get; private set; }

		public static ConfigEntry<string> InteriorsToSkipFallbackPortals { get; private set; }

		public static ConfigEntry<int> MaxBranchingDepth { get; private set; }

		public static ConfigEntry<bool> CullDistanceEnabled { get; private set; }

		public static ConfigEntry<float> CullDistance { get; private set; }

		public static ConfigEntry<float> SurfaceCullDistance { get; private set; }

		public static ConfigEntry<string> OverrideMapSeed { get; private set; }

		public static ConfigEntry<bool> VisualizePortals { get; private set; }

		public static ConfigEntry<float> VisualizedPortalOutsetDistance { get; private set; }

		public static ConfigEntry<bool> VisualizeTileBounds { get; private set; }

		public static string[] InteriorsWithFallbackPortals { get; private set; }

		public static void Initialize(ConfigFile configFile)
		{
			Culler = configFile.Bind<CullingType>("General", "Culling type", CullingType.PortalOcclusionCulling, "The culling type to use.\n\nOptions:\n\"PortalOcclusionCulling\": Hides all the rooms that aren't visible to the camera (Recommended)\n\"DepthCulling\": Hides rooms that aren't adjacent to the player's current room");
			InteriorsToBlockCulling = configFile.Bind<string>("General", "Disable culling for interiors", "", "A list of dungeon flows to disable culling on, separated by commas, i.e.\n\"Level1Flow, Level2Flow\"");
			InteriorsToForceCulling = configFile.Bind<string>("General", "Force enable culling for interiors", "", "A list of dungeon flows to ignore the blacklists and enable culling on, also separated by commas");
			UpdateFrequency = configFile.Bind<float>("General", "Update frequency", 0f, "Higher values make culling more responsive at the cost of performance.\nCurrently this has no effect when portal occlusion culling is used.\nUpdate interval: 1 / value (seconds)");
			DisableShadowDistanceFading = configFile.Bind<bool>("General", "Disable shadow distance fading", true, "Prevents lights' shadows from being hidden before the light itself becomes invisible.\nFixes issues that are common in Mansion where some lights will be visible through walls, and allows more lights/tiles to be culled within the interior.\nDisabling may have a negative impact on performance.");
			InteriorsToUseFallbackPortals = configFile.Bind<string>("Portal occlusion culling", "Use fallback portals for interiors", "", "Use a more forgiving testing method for the specified interiors.\nThis is recommended for interiors with incorrect portal sizes.\n\nValue:\nA list of dungeon generators, separated by commas \",\".");
			InteriorsToSkipFallbackPortals = configFile.Bind<string>("Portal occlusion culling", "Skip fallback portals for interiors", "", "Skip using fallback portals on previously problematic interiors:\n" + BaseSetOfInteriorsToSkipFallbackPortals.JoinByComma() + "\n\nValue:\nA list of dungeon generators, separated by commas \",\".");
			MaxBranchingDepth = configFile.Bind<int>("Depth culling", "Max branching depth", 4, "How many doors can be traversed before a room is culled.");
			CullDistanceEnabled = configFile.Bind<bool>("Distance culling", "Enabled", false, "Whether to override the camera's far plane distance. When this is false, the 'Cull distance' and 'Surface cull distance' options will have no effect.\nIf performance with portal occlusion culling enabled is insufficient this may provide a small boost in performance.");
			CullDistance = configFile.Bind<float>("Distance culling", "Cull distance", 40f, "The camera's far plane distance.\nObjects that are this far from the player will be culled.\nVanilla value: 400");
			SurfaceCullDistance = configFile.Bind<float>("Distance culling", "Surface cull distance", 200f, "The camera's far plane distance when **on the surface**.\nObjects that are this far from the player will be culled.\nVanilla value: 400");
			VisualizePortals = configFile.Bind<bool>("Debug", "Visualize portals", false, "Shows a rectangle representing the bounds of all portals that are used to determine visibility when portal occlusion culling is enabled. If the portal doesn't block the entirety of the visible portion of the next tile, then culling will not be correct.");
			VisualizedPortalOutsetDistance = configFile.Bind<float>("Debug", "Visualized portal outset distance", 0.2f, "The distance to offset each side of a portal visualizer out from the actual position of the portal. For doors that don't cover an entire tile wall, this allows seeing the exact bounds it covers.");
			VisualizeTileBounds = configFile.Bind<bool>("Debug", "Visualize tile bounds", false, "Shows a rectangular prism to represent the bounds all tiles. These bounds are used to determine which tile a camera resides in.");
			OverrideMapSeed = configFile.Bind<string>("Debug", "Override map seed", "", "INTENDED FOR BENCHMARKING ONLY. Leave this empty if you are playing normally.\nThis forces the map seed to be whatever is entered here, so that benchmarking numbers can remain as consistent as possible between runs.");
			Logging = configFile.Bind<bool>("Debug", "Show culling logs", false, "View culling activity in the console.");
			MigrateSettings();
			Culler.SettingChanged += delegate
			{
				CullingMethod.Initialize();
			};
			InteriorsToBlockCulling.SettingChanged += delegate
			{
				UpdateInteriorsWithDisabledCulling();
			};
			InteriorsToForceCulling.SettingChanged += delegate
			{
				UpdateInteriorsWithDisabledCulling();
			};
			UpdateFrequency.SettingChanged += delegate
			{
				CullingMethod.Initialize();
			};
			DisableShadowDistanceFading.SettingChanged += delegate
			{
				RefreshCullingInfoAndMethod();
			};
			InteriorsToUseFallbackPortals.SettingChanged += delegate
			{
				UpdateInteriorsWithFallbackPortals();
			};
			InteriorsToSkipFallbackPortals.SettingChanged += delegate
			{
				UpdateInteriorsWithFallbackPortals();
			};
			CullDistanceEnabled.SettingChanged += delegate
			{
				TeleportExtender.SetInitialFarClipPlane();
			};
			CullDistance.SettingChanged += delegate
			{
				TeleportExtender.SetInitialFarClipPlane();
			};
			SurfaceCullDistance.SettingChanged += delegate
			{
				TeleportExtender.SetInitialFarClipPlane();
			};
			VisualizePortals.SettingChanged += delegate
			{
				Plugin.CreateCullingVisualizers();
			};
			VisualizedPortalOutsetDistance.SettingChanged += delegate
			{
				Plugin.CreateCullingVisualizers();
			};
			VisualizeTileBounds.SettingChanged += delegate
			{
				Plugin.CreateCullingVisualizers();
			};
			UpdateInteriorsWithDisabledCulling();
			UpdateInteriorsWithFallbackPortals();
		}

		private static void MigrateSettings()
		{
			Version obj = (File.Exists(VersionFile) ? Version.Parse(Encoding.UTF8.GetString(File.ReadAllBytes(VersionFile))) : DefaultVersion);
			if (obj <= FallbackVersion)
			{
				InteriorsToUseFallbackPortals.Value = InteriorsToUseFallbackPortals.Value.SplitByComma().Except(BaseSetOfInteriorsToSkipFallbackPortals).JoinByComma();
			}
			if (obj <= new Version(0, 8, 6))
			{
				UpdateFrequency.Value = (float)((ConfigEntryBase)UpdateFrequency).DefaultValue;
			}
			using FileStream fileStream = File.Open(VersionFile, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
			fileStream.Write(Encoding.UTF8.GetBytes("1.0.0.5"));
		}

		private static void UpdateInteriorsWithDisabledCulling()
		{
			InteriorsWithDisabledCulling = DefaultFlowsToBlockCulling.Union(InteriorsToBlockCulling.Value.SplitByComma()).Except(InteriorsToForceCulling.Value.SplitByComma()).ToArray();
			CullingMethod.Initialize();
		}

		public static CullingType GetCullingType(DungeonFlow dungeonFlow)
		{
			if (InteriorsWithDisabledCulling.Contains(((Object)dungeonFlow).name))
			{
				return CullingType.None;
			}
			return Culler.Value;
		}

		private static void UpdateInteriorsWithFallbackPortals()
		{
			InteriorsWithFallbackPortals = BaseSetOfInteriorsToUseFallbackPortals.Union(InteriorsToUseFallbackPortals.Value.SplitByComma()).Except(InteriorsToSkipFallbackPortals.Value.SplitByComma()).ToArray();
			RefreshCullingInfoAndMethod();
		}

		private static void RefreshCullingInfoAndMethod()
		{
			DungeonCullingInfo.RefreshCullingInfo();
			CullingMethod.Initialize();
		}
	}
	[BepInPlugin("com.fumiko.CullFactory", "CullFactory", "1.0.0.5")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.fumiko.CullFactory";

		public const string Name = "CullFactory";

		public const string Version = "1.0.0.5";

		public static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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)
			Instance = this;
			Config.Initialize(((BaseUnityPlugin)this).Config);
			Harmony val = new Harmony("com.fumiko.CullFactory");
			val.PatchAll(typeof(LevelGenerationExtender));
			val.PatchAll(typeof(TeleportExtender));
			val.PatchAll(typeof(MapSeedOverride));
			val.PatchAll(typeof(GrabbableObjectExtender));
			QualitySettings.shadowResolution = (ShadowResolution)0;
			Log("Plugin CullFactory is loaded!");
		}

		public static void LogAlways(string s)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)s);
		}

		public static void Log(string s)
		{
			if (Config.Logging.Value)
			{
				LogAlways(s);
			}
		}

		public static void LogWarning(string s)
		{
			((BaseUnityPlugin)Instance).Logger.LogWarning((object)s);
		}

		public static void LogError(string s)
		{
			((BaseUnityPlugin)Instance).Logger.LogError((object)s);
		}

		public static void CreateCullingVisualizers()
		{
			if (!((Object)(object)RoundManager.Instance.dungeonGenerator == (Object)null))
			{
				GameObject gameObject = ((Component)RoundManager.Instance.dungeonGenerator.Generator.CurrentDungeon).gameObject;
				Object.DestroyImmediate((Object)(object)gameObject.GetComponent<CullingVisualizer>());
				gameObject.AddComponent<CullingVisualizer>().RefreshVisualizers();
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "CullFactory";

		public const string PLUGIN_NAME = "CullFactory";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace CullFactory.Services
{
	public static class BoundsUtility
	{
		public static Plane[] GetPlanes(this Bounds bounds)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			return (Plane[])(object)new Plane[6]
			{
				new Plane(new Vector3(1f, 0f, 0f), 0f - ((Bounds)(ref bounds)).min.x),
				new Plane(new Vector3(0f, 1f, 0f), 0f - ((Bounds)(ref bounds)).min.y),
				new Plane(new Vector3(0f, 0f, 1f), 0f - ((Bounds)(ref bounds)).min.z),
				new Plane(new Vector3(-1f, 0f, 0f), ((Bounds)(ref bounds)).max.x),
				new Plane(new Vector3(0f, -1f, 0f), ((Bounds)(ref bounds)).max.y),
				new Plane(new Vector3(0f, 0f, -1f), ((Bounds)(ref bounds)).max.z)
			};
		}

		public static void GetFarthestPlanesNonAlloc(this Bounds bounds, Vector3 point, Plane[] planes)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			planes[0] = ((point.x > ((Bounds)(ref bounds)).center.x) ? new Plane(new Vector3(1f, 0f, 0f), 0f - ((Bounds)(ref bounds)).min.x) : new Plane(new Vector3(-1f, 0f, 0f), ((Bounds)(ref bounds)).max.x));
			planes[1] = ((point.y > ((Bounds)(ref bounds)).center.y) ? new Plane(new Vector3(0f, 1f, 0f), 0f - ((Bounds)(ref bounds)).min.y) : new Plane(new Vector3(0f, -1f, 0f), ((Bounds)(ref bounds)).max.y));
			planes[2] = ((point.z > ((Bounds)(ref bounds)).center.z) ? new Plane(new Vector3(0f, 0f, 1f), 0f - ((Bounds)(ref bounds)).min.z) : new Plane(new Vector3(0f, 0f, -1f), ((Bounds)(ref bounds)).max.z));
		}

		public static Plane[] GetFarthestPlanes(this Bounds bounds, Vector3 point)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			Plane[] array = (Plane[])(object)new Plane[3];
			bounds.GetFarthestPlanesNonAlloc(point, array);
			return array;
		}

		public static Vector3[] GetVertices(Vector3 min, Vector3 max)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_0050: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: 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_00f1: Unknown result type (might be due to invalid IL or missing references)
			return (Vector3[])(object)new Vector3[8]
			{
				new Vector3(min.x, min.y, min.z),
				new Vector3(max.x, min.y, min.z),
				new Vector3(min.x, max.y, min.z),
				new Vector3(max.x, max.y, min.z),
				new Vector3(min.x, min.y, max.z),
				new Vector3(max.x, min.y, max.z),
				new Vector3(min.x, max.y, max.z),
				new Vector3(max.x, max.y, max.z)
			};
		}

		public static Vector3[] GetVertices(this Bounds bounds)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			return GetVertices(((Bounds)(ref bounds)).min, ((Bounds)(ref bounds)).max);
		}
	}
	public static class LightUtility
	{
		public static bool Affects(this Light light, Bounds bounds)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			float range = light.range;
			if (((Bounds)(ref bounds)).SqrDistance(((Component)light).transform.position) > range * range)
			{
				return false;
			}
			return true;
		}

		public static bool Affects(this Light light, TileContents tile)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return light.Affects(tile.bounds);
		}

		public static bool Affects(this Light light, IEnumerable<TileContents> tiles)
		{
			foreach (TileContents tile in tiles)
			{
				if (light.Affects(tile))
				{
					return true;
				}
			}
			return false;
		}

		public static bool HasShadows(this Light light)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			return (int)light.shadows > 0;
		}

		public static bool PassesThroughOccluders(this Light light)
		{
			if (light.HasShadows())
			{
				HDAdditionalLightData component = ((Component)light).GetComponent<HDAdditionalLightData>();
				if (component != null)
				{
					return component.shadowDimmer < 1f;
				}
				return false;
			}
			return true;
		}

		public static void SetVisible(this Light light, bool visible)
		{
			if (light.cullingMask != -1 && light.cullingMask != 0)
			{
				Plugin.LogWarning($"Light {((Object)light).name}'s culling mask was an unexpected value of {light.cullingMask}.");
			}
			light.cullingMask = (visible ? (-1) : 0);
		}

		public static void SetVisible(this IEnumerable<Light> lights, bool visible)
		{
			foreach (Light light in lights)
			{
				if (!((Object)(object)light == (Object)null))
				{
					light.SetVisible(visible);
				}
			}
		}
	}
	public static class ObjectContentsUtility
	{
		public static void SetSelfVisible(this IEnumerable<TileContents> tiles, bool visible)
		{
			foreach (TileContents tile in tiles)
			{
				tile.SetSelfVisible(visible);
			}
		}

		public static void SetVisible(this IEnumerable<GrabbableObjectContents> items, bool visible)
		{
			foreach (GrabbableObjectContents item in items)
			{
				item.SetVisible(visible);
			}
		}

		public static void AddContentsVisibleToCamera(this ICollection<TileContents> result, Camera camera)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (camera.orthographic)
			{
				result.AddContentsWithinCameraFrustum(camera);
				return;
			}
			TileContents tileContents = ((Component)camera).transform.position.GetTileContents();
			if (tileContents != null)
			{
				VisibilityTesting.CallForEachLineOfSight(camera, tileContents, delegate(TileContents[] tiles, Plane[][] frustums, int index)
				{
					result.Add(tiles[index]);
				});
			}
		}

		public static void AddContentsWithinCameraFrustum(this ICollection<TileContents> result, Camera camera)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			Plane[] array = GeometryUtility.CalculateFrustumPlanes(camera);
			TileContents[] allTileContents = DungeonCullingInfo.AllTileContents;
			foreach (TileContents tileContents in allTileContents)
			{
				if (GeometryUtility.TestPlanesAABB(array, tileContents.bounds))
				{
					result.Add(tileContents);
				}
			}
		}
	}
	public static class StringUtility
	{
		public static IEnumerable<string> SplitByComma(this string input)
		{
			return from name in input.Split(',', StringSplitOptions.RemoveEmptyEntries)
				select name.Trim().Trim('"');
		}

		public static string JoinByComma(this IEnumerable<string> input)
		{
			return string.Join(", ", input);
		}

		public static string GetPath(this Transform obj)
		{
			StringBuilder stringBuilder = new StringBuilder(((Object)obj).name);
			Transform parent = obj.parent;
			while ((Object)(object)parent != (Object)null)
			{
				stringBuilder.Insert(0, "/");
				stringBuilder.Insert(0, ((Object)parent).name);
				parent = parent.parent;
			}
			return stringBuilder.ToString();
		}
	}
	public static class VisibilityTesting
	{
		public delegate void LineOfSightCallback(TileContents[] tileStack, Plane[][] frustumStack, int stackIndex);

		private const int MaxStackCapacity = 16;

		private static readonly TileContents[] TileStack = new TileContents[16];

		private static readonly int[] IndexStack = new int[16];

		private static readonly Plane[][] FrustumStack = new Plane[16][];

		private static bool warnedThatStackWasExceeded = false;

		internal static bool IntersectsFrustums(this Bounds bounds, Plane[][] frustums, int lastFrustum)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i <= lastFrustum; i++)
			{
				if (!GeometryUtility.TestPlanesAABB(frustums[i], bounds))
				{
					return false;
				}
			}
			return true;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static bool AdvanceToNextTile(Vector3 origin, ref int stackIndex)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			TileContents tileContents = TileStack[stackIndex];
			int num = IndexStack[stackIndex]++;
			if (num >= tileContents.portals.Length)
			{
				stackIndex--;
				return false;
			}
			Portal portal = tileContents.portals[num];
			TileContents nextTile = portal.NextTile;
			if (nextTile == null)
			{
				return false;
			}
			if (stackIndex > 0 && nextTile == TileStack[stackIndex - 1])
			{
				return false;
			}
			if (!portal.Bounds.IntersectsFrustums(FrustumStack, stackIndex))
			{
				return false;
			}
			stackIndex++;
			if (stackIndex >= 16)
			{
				stackIndex--;
				if (!warnedThatStackWasExceeded)
				{
					Plugin.LogWarning($"Exceeded the maximum portal occlusion culling depth of {16}.");
					warnedThatStackWasExceeded = true;
				}
				return false;
			}
			TileStack[stackIndex] = nextTile;
			IndexStack[stackIndex] = 0;
			if (FrustumStack[stackIndex] == null)
			{
				FrustumStack[stackIndex] = portal.GetFrustumPlanes(origin);
			}
			else
			{
				portal.GetFrustumPlanesNonAlloc(origin, FrustumStack[stackIndex]);
			}
			return true;
		}

		public static void CallForEachLineOfSight(Vector3 origin, TileContents originTile, Plane[] frustum, LineOfSightCallback callback)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			TileStack[0] = originTile;
			IndexStack[0] = 0;
			FrustumStack[0] = frustum;
			int stackIndex = 0;
			callback(TileStack, FrustumStack, stackIndex);
			while (stackIndex >= 0)
			{
				if (AdvanceToNextTile(origin, ref stackIndex))
				{
					callback(TileStack, FrustumStack, stackIndex);
				}
			}
		}

		public static void CallForEachLineOfSight(Camera camera, TileContents originTile, LineOfSightCallback callback)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			CallForEachLineOfSight(((Component)camera).transform.position, originTile, GeometryUtility.CalculateFrustumPlanes(camera), callback);
		}

		public static void CallForEachLineOfSight(Vector3 origin, TileContents originTile, LineOfSightCallback callback)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			CallForEachLineOfSight(origin, originTile, Array.Empty<Plane>(), callback);
		}

		private static bool FrustumIntersectsAnyTile(Plane[] frustum, HashSet<TileContents> tiles)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			foreach (TileContents tile in tiles)
			{
				if (GeometryUtility.TestPlanesAABB(frustum, tile.bounds))
				{
					return true;
				}
			}
			return false;
		}

		public static bool CallForEachLineOfSightTowardTiles(Vector3 origin, TileContents originTile, Plane[] frustum, HashSet<TileContents> goalTiles, LineOfSightCallback callback)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			TileStack[0] = originTile;
			IndexStack[0] = 0;
			FrustumStack[0] = frustum;
			int stackIndex = 0;
			callback(TileStack, FrustumStack, stackIndex);
			bool result = goalTiles.Contains(originTile);
			while (stackIndex >= 0)
			{
				if (!AdvanceToNextTile(origin, ref stackIndex))
				{
					continue;
				}
				if (!FrustumIntersectsAnyTile(FrustumStack[stackIndex], goalTiles))
				{
					stackIndex--;
					continue;
				}
				if (goalTiles.Contains(TileStack[stackIndex]))
				{
					result = true;
				}
				callback(TileStack, FrustumStack, stackIndex);
			}
			return result;
		}

		public static bool CallForEachLineOfSightTowardTiles(Vector3 origin, TileContents originTile, HashSet<TileContents> goalTiles, LineOfSightCallback callback)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return CallForEachLineOfSightTowardTiles(origin, originTile, Array.Empty<Plane>(), goalTiles, callback);
		}
	}
}
namespace CullFactory.Extenders
{
	internal class GrabbableObjectExtender
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(GrabbableObject), "Start")]
		private static void GrabbableObjectStarted(GrabbableObject __instance)
		{
			DynamicObjects.RefreshGrabbableObject(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GrabbableObject), "EnablePhysics")]
		private static void GrabbableObjectDropped(GrabbableObject __instance)
		{
			DynamicObjects.RefreshGrabbableObject(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GrabbableObject), "EnableItemMeshes")]
		private static void GrabbableObjectShownOrHidden(GrabbableObject __instance)
		{
			DynamicObjects.RefreshGrabbableObject(__instance);
		}
	}
	public sealed class LevelGenerationExtender
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(RoundManager), "waitForMainEntranceTeleportToSpawn")]
		private static void OnLevelGenerated()
		{
			DungeonCullingInfo.OnLevelGenerated();
			CullingMethod.Initialize();
			Plugin.CreateCullingVisualizers();
			DynamicObjects.CollectAllTrackedObjects();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StartOfRound), "PassTimeToNextDay")]
		private static void OnRoundEnded()
		{
			DungeonCullingInfo.ClearAll();
			DynamicObjects.CollectAllTrackedObjects();
		}
	}
	internal class MapSeedOverride
	{
		[HarmonyPatch(typeof(StartOfRound), "Start")]
		[HarmonyPostfix]
		private static void StartOfRound_StartPostfix(StartOfRound __instance)
		{
			if (int.TryParse(Config.OverrideMapSeed.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
			{
				__instance.overrideRandomSeed = true;
				__instance.overrideSeedNumber = result;
			}
			else
			{
				__instance.overrideRandomSeed = false;
			}
		}
	}
	[HarmonyPatch(typeof(EntranceTeleport))]
	public static class TeleportExtender
	{
		private static float[] _initialPlayerCameraFarPlanes;

		public static void SetInitialFarClipPlane()
		{
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			if (_initialPlayerCameraFarPlanes == null)
			{
				_initialPlayerCameraFarPlanes = new float[allPlayerScripts.Length];
				for (int i = 0; i < allPlayerScripts.Length; i++)
				{
					_initialPlayerCameraFarPlanes[i] = allPlayerScripts[i].gameplayCamera.farClipPlane;
				}
			}
			if (!Config.CullDistanceEnabled.Value)
			{
				for (int j = 0; j < allPlayerScripts.Length; j++)
				{
					allPlayerScripts[j].gameplayCamera.farClipPlane = _initialPlayerCameraFarPlanes[j];
				}
				return;
			}
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				val.gameplayCamera.farClipPlane = (val.isInsideFactory ? Config.CullDistance.Value : Config.SurfaceCullDistance.Value);
				Plugin.Log($"Set culling distance of \"{((Object)val.gameplayCamera).name}\" to {val.gameplayCamera.farClipPlane}");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
		private static void LocalPlayerTookControl()
		{
			SetInitialFarClipPlane();
			DynamicObjects.CollectAllPlayerLights();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerControllerB), "TeleportPlayer")]
		private static void OnTeleportPlayerController(PlayerControllerB __instance)
		{
			OnPlayerTeleported(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(EntranceTeleport), "TeleportPlayer")]
		private static void OnTeleportLocalPlayerThroughEntrance()
		{
			OnPlayerTeleported(StartOfRound.Instance.localPlayerController);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(EntranceTeleport), "TeleportPlayerClientRpc")]
		private static void OnTeleportOtherPlayerThroughEntrance(ref int playerObj)
		{
			PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[playerObj];
			if (!((Object)(object)val == (Object)(object)StartOfRound.Instance.localPlayerController))
			{
				OnPlayerTeleported(val);
			}
		}

		private static void OnPlayerTeleported(PlayerControllerB player)
		{
			UpdateFarPlane(player);
			DynamicObjects.OnPlayerTeleported(player);
		}

		private static void UpdateFarPlane(PlayerControllerB player)
		{
			if (Config.CullDistanceEnabled.Value)
			{
				player.gameplayCamera.farClipPlane = (player.isInsideFactory ? Config.CullDistance.Value : Config.SurfaceCullDistance.Value);
				Plugin.Log(string.Format("{0} is{1} in the factory, set far plane distance to {2}", player.playerUsername, player.isInsideFactory ? string.Empty : " not", player.gameplayCamera.farClipPlane));
			}
		}
	}
}
namespace CullFactory.Data
{
	public enum CullingType
	{
		None,
		PortalOcclusionCulling,
		DepthCulling
	}
	public static class DungeonCullingInfo
	{
		private const float OutsideTileRadius = 10f;

		private const float SqrOutsideTileRadius = 100f;

		private const int RendererIntrusionTileDepth = 2;

		private const float RendererIntrusionDistance = 0.01f;

		public static Bounds DungeonBounds;

		public static TileContents[] AllTileContents { get; private set; }

		public static Dictionary<Tile, TileContents> TileContentsForTile { get; private set; }

		public static Light[] AllLightsInDungeon { get; private set; }

		public static void OnLevelGenerated()
		{
			string name = ((Object)RoundManager.Instance.dungeonGenerator.Generator.DungeonFlow).name;
			Plugin.LogAlways($"{name} has finished generating with seed {StartOfRound.Instance.randomMapSeed}.");
			bool num = Array.IndexOf(Config.InteriorsWithFallbackPortals, name) != -1;
			if (num)
			{
				Plugin.LogAlways("Using tile bounds to determine the size of portals for " + name + ".");
			}
			double realtimeSinceStartupAsDouble = Time.realtimeSinceStartupAsDouble;
			CollectAllTileContents(num);
			Plugin.Log($"Preparing tile information for the dungeon took {(Time.realtimeSinceStartupAsDouble - realtimeSinceStartupAsDouble) * 1000.0:0.###}ms");
		}

		public static void ClearAll()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (AllTileContents != null)
			{
				AllTileContents = Array.Empty<TileContents>();
				TileContentsForTile.Clear();
				AllLightsInDungeon = Array.Empty<Light>();
				DungeonBounds = default(Bounds);
			}
		}

		public static void RefreshCullingInfo()
		{
			if (AllTileContents != null)
			{
				OnLevelGenerated();
			}
		}

		private static void AddIntersectingRenderers(Bounds bounds, HashSet<Renderer> toCollection, HashSet<TileContents> visitedTiles, TileContents currentTile, int tilesLeft)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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)
			if (!visitedTiles.Add(currentTile))
			{
				return;
			}
			Renderer[] renderers = currentTile.renderers;
			foreach (Renderer val in renderers)
			{
				Bounds bounds2 = val.bounds;
				if (((Bounds)(ref bounds2)).Intersects(bounds))
				{
					toCollection.Add(val);
				}
			}
			if (--tilesLeft > 0)
			{
				Portal[] portals = currentTile.portals;
				foreach (Portal portal in portals)
				{
					AddIntersectingRenderers(bounds, toCollection, visitedTiles, portal.NextTile, tilesLeft - 1);
				}
			}
			visitedTiles.Remove(currentTile);
		}

		private static HashSet<Renderer> GetIntrudingRenderers(TileContents originTile)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			HashSet<Renderer> hashSet = new HashSet<Renderer>();
			Bounds bounds = originTile.bounds;
			((Bounds)(ref bounds)).Expand(-0.01f);
			HashSet<TileContents> visitedTiles = new HashSet<TileContents> { originTile };
			Portal[] portals = originTile.portals;
			foreach (Portal portal in portals)
			{
				AddIntersectingRenderers(bounds, hashSet, visitedTiles, portal.NextTile, 2);
			}
			return hashSet;
		}

		private static void CollectAllTileContents(bool derivePortalBoundsFromTile)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
			ReadOnlyCollection<Tile> allTiles = RoundManager.Instance.dungeonGenerator.Generator.CurrentDungeon.AllTiles;
			TileContentsForTile = new Dictionary<Tile, TileContents>(allTiles.Count);
			List<Light> list = new List<Light>();
			Vector3 val = Vector3.positiveInfinity;
			Vector3 val2 = Vector3.negativeInfinity;
			foreach (Tile item in allTiles)
			{
				TileContents tileContents = new TileContents(item);
				TileContentsForTile[item] = tileContents;
				list.AddRange(tileContents.lights);
				Vector3 val3 = val;
				Bounds bounds = tileContents.bounds;
				val = Vector3.Min(val3, ((Bounds)(ref bounds)).min);
				Vector3 val4 = val2;
				bounds = tileContents.bounds;
				val2 = Vector3.Max(val4, ((Bounds)(ref bounds)).max);
			}
			AllTileContents = new TileContents[TileContentsForTile.Count];
			int num = 0;
			int num2;
			foreach (TileContents value in TileContentsForTile.Values)
			{
				List<Doorway> usedDoorways = value.tile.UsedDoorways;
				int count = usedDoorways.Count;
				List<Portal> list2 = new List<Portal>(count);
				for (int i = 0; i < count; i++)
				{
					Doorway val5 = usedDoorways[i];
					if (!((Object)(object)val5.ConnectedDoorway == (Object)null))
					{
						list2.Add(new Portal(val5, derivePortalBoundsFromTile, TileContentsForTile[val5.ConnectedDoorway.Tile]));
					}
				}
				TileContents tileContents2 = value;
				num2 = 0;
				Portal[] array = new Portal[list2.Count];
				foreach (Portal item2 in list2)
				{
					array[num2] = item2;
					num2++;
				}
				tileContents2.portals = array;
				AllTileContents[num++] = value;
			}
			num2 = 0;
			Light[] array2 = (Light[])(object)new Light[list.Count];
			foreach (Light item3 in list)
			{
				array2[num2] = item3;
				num2++;
			}
			AllLightsInDungeon = array2;
			((Bounds)(ref DungeonBounds)).min = val;
			((Bounds)(ref DungeonBounds)).max = val2;
			HashSet<Renderer>[] array3 = new HashSet<Renderer>[AllTileContents.Length];
			for (num = 0; num < AllTileContents.Length; num++)
			{
				array3[num] = GetIntrudingRenderers(AllTileContents[num]);
			}
			for (num = 0; num < AllTileContents.Length; num++)
			{
				TileContents tileContents2;
				Renderer[] renderers = (tileContents2 = AllTileContents[num]).renderers;
				HashSet<Renderer> hashSet = array3[num];
				num2 = 0;
				Renderer[] array4 = (Renderer[])(object)new Renderer[renderers.Length + hashSet.Count];
				Renderer[] array5 = renderers;
				foreach (Renderer val6 in array5)
				{
					array4[num2] = val6;
					num2++;
				}
				foreach (Renderer item4 in hashSet)
				{
					array4[num2] = item4;
					num2++;
				}
				tileContents2.renderers = array4;
			}
			foreach (var item5 in AllTileContents.SelectMany((TileContents tile) => tile.lights.Select((Light light) => (tile, light))))
			{
				var (tileContents3, light2) = item5;
				if (!((Component)light2).gameObject.activeInHierarchy)
				{
					continue;
				}
				bool flag = light2.HasShadows();
				bool lightPassesThroughWalls = !Config.DisableShadowDistanceFading.Value || light2.PassesThroughOccluders();
				if (lightPassesThroughWalls)
				{
					TileContents[] allTileContents = AllTileContents;
					foreach (TileContents tileContents4 in allTileContents)
					{
						if (!light2.Affects(tileContents4.bounds))
						{
							continue;
						}
						TileContents tileContents2 = tileContents4;
						array2 = tileContents4.externalLights;
						int j = 0;
						Light[] array6 = (Light[])(object)new Light[1 + array2.Length];
						Light[] array7 = array2;
						foreach (Light current4 in array7)
						{
							array6[j] = current4;
							j++;
						}
						array6[j] = light2;
						j++;
						tileContents2.externalLights = array6;
						if (!flag)
						{
							continue;
						}
						tileContents2 = tileContents4;
						List<Renderer> list3 = new List<Renderer>();
						foreach (Renderer item6 in tileContents4.externalRenderers.Union(tileContents3.renderers))
						{
							list3.Add(item6);
						}
						tileContents2.externalRenderers = list3.ToArray();
					}
				}
				if (!flag)
				{
					continue;
				}
				Vector3 lightOrigin = ((Component)light2).transform.position;
				VisibilityTesting.CallForEachLineOfSight(lightOrigin, tileContents3, delegate(TileContents[] tiles, Plane[][] frustums, int index)
				{
					//IL_0010: 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_0052: Unknown result type (might be due to invalid IL or missing references)
					//IL_005b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0106: Unknown result type (might be due to invalid IL or missing references)
					//IL_010c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0185: 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_0190: Unknown result type (might be due to invalid IL or missing references)
					//IL_0192: Unknown result type (might be due to invalid IL or missing references)
					if (index >= 1)
					{
						TileContents tileContents5 = tiles[index];
						if (light2.Affects(tileContents5.bounds))
						{
							bool flag2 = false;
							List<Renderer> list4 = new List<Renderer>();
							for (int num3 = index - 1; num3 >= 0; num3--)
							{
								Renderer[] renderers2 = tiles[num3].renderers;
								foreach (Renderer val7 in renderers2)
								{
									Bounds bounds2 = val7.bounds;
									if (light2.Affects(bounds2) && bounds2.IntersectsFrustums(frustums, num3))
									{
										flag2 = true;
										list4.Add(val7);
									}
								}
							}
							TileContents tileContents6 = tileContents5;
							List<Renderer> list5 = new List<Renderer>();
							foreach (Renderer item7 in tileContents5.externalRenderers.Union(list4))
							{
								list5.Add(item7);
							}
							tileContents6.externalRenderers = list5.ToArray();
							if (flag2)
							{
								List<Plane> list6 = new List<Plane>();
								for (int m = 1; m <= index; m++)
								{
									list6.AddRange(frustums[m]);
								}
								list6.AddRange(tileContents5.bounds.GetFarthestPlanes(lightOrigin));
								tileContents6 = tileContents5;
								Plane[][] externalLightLinesOfSight = tileContents5.externalLightLinesOfSight;
								int num4 = 0;
								Plane[][] array8 = new Plane[1 + externalLightLinesOfSight.Length][];
								Plane[][] array9 = externalLightLinesOfSight;
								foreach (Plane[] array10 in array9)
								{
									array8[num4] = array10;
									num4++;
								}
								Plane[][] array11 = array8;
								int l = num4;
								int num5 = 0;
								Plane[] array12 = (Plane[])(object)new Plane[list6.Count];
								foreach (Plane item8 in list6)
								{
									array12[num5] = item8;
									num5++;
								}
								array11[l] = array12;
								num4++;
								tileContents6.externalLightLinesOfSight = array8;
								if (!lightPassesThroughWalls)
								{
									tileContents6 = tileContents5;
									Light[] externalLights = tileContents5.externalLights;
									num4 = 0;
									Light[] array13 = (Light[])(object)new Light[1 + externalLights.Length];
									Light[] array14 = externalLights;
									foreach (Light val8 in array14)
									{
										array13[num4] = val8;
										num4++;
									}
									array13[num4] = light2;
									num4++;
									tileContents6.externalLights = array13;
								}
							}
						}
					}
				});
			}
		}

		public static TileContents GetTileContents(this Vector3 point)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			float num = 100f;
			TileContents result = null;
			TileContents[] allTileContents = AllTileContents;
			foreach (TileContents tileContents in allTileContents)
			{
				Bounds bounds = tileContents.bounds;
				if (((Bounds)(ref bounds)).Contains(point))
				{
					return tileContents;
				}
				bounds = tileContents.bounds;
				float num2 = ((Bounds)(ref bounds)).SqrDistance(point);
				if (!(num2 > num))
				{
					num = num2;
					result = tileContents;
				}
			}
			return result;
		}

		public static void CollectAllTilesWithinCameraFrustum(Camera camera, List<TileContents> intoList)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			Plane[] array = GeometryUtility.CalculateFrustumPlanes(camera);
			TileContents[] allTileContents = AllTileContents;
			foreach (TileContents tileContents in allTileContents)
			{
				if (GeometryUtility.TestPlanesAABB(array, tileContents.bounds))
				{
					intoList.Add(tileContents);
				}
			}
		}
	}
	public static class DynamicObjects
	{
		public static readonly HashSet<Light> AllLightsOutside = new HashSet<Light>();

		public static readonly HashSet<Light> AllLightsInInterior = new HashSet<Light>();

		public static HashSet<GrabbableObjectContents> AllGrabbableObjectContentsOutside = new HashSet<GrabbableObjectContents>();

		public static HashSet<GrabbableObjectContents> AllGrabbableObjectContentsInInterior = new HashSet<GrabbableObjectContents>();

		public static Dictionary<GrabbableObject, GrabbableObjectContents> GrabbableObjectToContents = new Dictionary<GrabbableObject, GrabbableObjectContents>();

		private static Light[][] allPlayerLights;

		internal static void CollectAllPlayerLights()
		{
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			int num = allPlayerScripts.Length;
			allPlayerLights = new Light[num][];
			for (int i = 0; i < num; i++)
			{
				if (!((Object)(object)allPlayerScripts[i] == (Object)null))
				{
					allPlayerLights[i] = ((Component)allPlayerScripts[i]).GetComponentsInChildren<Light>(true);
				}
			}
		}

		internal static void RefreshGrabbableObject(GrabbableObject item)
		{
			//IL_00a9: 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)
			if (GrabbableObjectToContents.TryGetValue(item, out var value))
			{
				Plugin.Log("Refreshing contents of " + ((Object)item).name);
				AllLightsOutside.ExceptWith(value.lights);
				AllLightsInInterior.ExceptWith(value.lights);
				value.CollectContents();
			}
			else
			{
				Plugin.Log("Adding contents of " + ((Object)item).name);
				value = new GrabbableObjectContents(item);
				GrabbableObjectToContents[item] = value;
			}
			bool flag;
			if (item.playerHeldBy == null)
			{
				ScanNodeProperties componentInChildren = ((Component)item).GetComponentInChildren<ScanNodeProperties>();
				flag = ((componentInChildren == null) ? ((Bounds)(ref DungeonCullingInfo.DungeonBounds)).Contains(((Component)item).transform.position) : ((Bounds)(ref DungeonCullingInfo.DungeonBounds)).Contains(((Component)componentInChildren).transform.position));
			}
			else
			{
				flag = item.playerHeldBy.isInsideFactory;
			}
			if (flag)
			{
				AllLightsOutside.ExceptWith(value.lights);
				AllLightsInInterior.UnionWith(value.lights);
				AllGrabbableObjectContentsOutside.Remove(value);
				AllGrabbableObjectContentsInInterior.Add(value);
			}
			else
			{
				AllLightsOutside.UnionWith(value.lights);
				AllLightsInInterior.ExceptWith(value.lights);
				AllGrabbableObjectContentsOutside.Add(value);
				AllGrabbableObjectContentsInInterior.Remove(value);
			}
		}

		internal static void OnPlayerTeleported(PlayerControllerB player)
		{
			CollectAllPlayerLights();
			int num = Array.IndexOf(StartOfRound.Instance.allPlayerScripts, player);
			if (num == -1)
			{
				return;
			}
			Light[] other = allPlayerLights[num];
			if (player.isInsideFactory)
			{
				AllLightsOutside.ExceptWith(other);
				AllLightsInInterior.UnionWith(other);
			}
			else
			{
				AllLightsOutside.UnionWith(other);
				AllLightsInInterior.ExceptWith(other);
			}
			GrabbableObject[] itemSlots = player.ItemSlots;
			foreach (GrabbableObject val in itemSlots)
			{
				if (!((Object)(object)val == (Object)null))
				{
					RefreshGrabbableObject(val);
				}
			}
		}

		internal static void CollectAllTrackedObjects()
		{
			AllLightsOutside.Clear();
			AllLightsInInterior.Clear();
			AllGrabbableObjectContentsOutside.Clear();
			AllGrabbableObjectContentsInInterior.Clear();
			GrabbableObjectToContents.Clear();
			IEnumerable<Light> enumerable = Object.FindObjectsByType<Light>((FindObjectsInactive)1, (FindObjectsSortMode)0).AsEnumerable();
			if (DungeonCullingInfo.AllLightsInDungeon != null)
			{
				enumerable = enumerable.Except(DungeonCullingInfo.AllLightsInDungeon);
			}
			AllLightsOutside.UnionWith(enumerable.Where((Light light) => !((Bounds)(ref DungeonCullingInfo.DungeonBounds)).Contains(((Component)light).transform.position)));
			AllLightsInInterior.UnionWith(enumerable.Except(AllLightsOutside));
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			for (int i = 0; i < allPlayerScripts.Length; i++)
			{
				OnPlayerTeleported(allPlayerScripts[i]);
			}
			GrabbableObject[] array = Object.FindObjectsByType<GrabbableObject>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				RefreshGrabbableObject(array[i]);
			}
			CullingMethod.Instance?.OnDynamicLightsCollected();
		}
	}
	public sealed class GrabbableObjectContents
	{
		public static readonly Vector3 Vector3NaN = new Vector3(float.NaN, float.NaN, float.NaN);

		public readonly GrabbableObject item;

		public Renderer[] renderers;

		public Light[] lights;

		public Vector3[] boundingVertices;

		public Bounds bounds;

		public bool HasBounds
		{
			get
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: 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_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0083: Unknown result type (might be due to invalid IL or missing references)
				if (float.IsNaN(((Bounds)(ref bounds)).center.x))
				{
					return false;
				}
				if (float.IsNaN(((Bounds)(ref bounds)).center.y))
				{
					return false;
				}
				if (float.IsNaN(((Bounds)(ref bounds)).center.z))
				{
					return false;
				}
				if (float.IsNaN(((Bounds)(ref bounds)).extents.x))
				{
					return false;
				}
				if (float.IsNaN(((Bounds)(ref bounds)).extents.y))
				{
					return false;
				}
				if (float.IsNaN(((Bounds)(ref bounds)).extents.z))
				{
					return false;
				}
				return true;
			}
		}

		public GrabbableObjectContents(GrabbableObject item)
		{
			this.item = item;
			CollectContents();
		}

		public void CollectContents()
		{
			renderers = ((Component)item).GetComponentsInChildren<Renderer>();
			lights = ((Component)item).GetComponentsInChildren<Light>();
			CalculateLocalBounds();
		}

		private void CalculateLocalBounds()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.positiveInfinity;
			Vector3 val2 = Vector3.negativeInfinity;
			Renderer[] array = renderers;
			foreach (Renderer val3 in array)
			{
				if (!((Object)(object)val3 == (Object)null) && val3.enabled && ((Component)val3).gameObject.activeInHierarchy)
				{
					Bounds val4 = val3.bounds;
					val = Vector3.Min(val, ((Bounds)(ref val4)).min);
					val2 = Vector3.Max(val2, ((Bounds)(ref val4)).max);
				}
			}
			if (((Vector3)(ref val)).Equals(Vector3.positiveInfinity) || ((Vector3)(ref val2)).Equals(Vector3.negativeInfinity))
			{
				boundingVertices = Array.Empty<Vector3>();
				return;
			}
			boundingVertices = BoundsUtility.GetVertices(val, val2);
			((Component)item).transform.InverseTransformPoints((Span<Vector3>)boundingVertices);
			CalculateBounds();
		}

		public void CalculateBounds()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if (boundingVertices.Length == 0 || (Object)(object)item == (Object)null)
			{
				bounds = new Bounds(Vector3NaN, Vector3NaN);
			}
			else
			{
				bounds = GeometryUtility.CalculateBounds(boundingVertices, ((Component)item).transform.localToWorldMatrix);
			}
		}

		public bool IsVisible(Plane[] planes)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (!HasBounds)
			{
				return false;
			}
			return GeometryUtility.TestPlanesAABB(planes, bounds);
		}

		public bool IsVisible(Plane[][] planes, int lastIndex)
		{
			for (int i = 0; i <= lastIndex; i++)
			{
				if (!IsVisible(planes[i]))
				{
					return false;
				}
			}
			return true;
		}

		public bool IsWithin(Bounds bounds)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			if (!HasBounds)
			{
				return false;
			}
			return ((Bounds)(ref this.bounds)).Intersects(bounds);
		}

		public bool IsWithin(TileContents tile)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return IsWithin(tile.bounds);
		}

		public bool IsWithin(IEnumerable<TileContents> tiles)
		{
			foreach (TileContents tile in tiles)
			{
				if (IsWithin(tile))
				{
					return true;
				}
			}
			return false;
		}

		public void SetVisible(bool visible)
		{
			Renderer[] array = renderers;
			foreach (Renderer val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					val.forceRenderingOff = !visible;
				}
			}
		}

		public override string ToString()
		{
			if ((Object)(object)item == (Object)null)
			{
				return "Destroyed";
			}
			return ((Object)item).name;
		}

		public override int GetHashCode()
		{
			return ((object)item).GetHashCode();
		}

		public override bool Equals(object obj)
		{
			if (obj is GrabbableObjectContents grabbableObjectContents)
			{
				return ((object)item).Equals((object?)grabbableObjectContents.item);
			}
			return false;
		}
	}
	public class Portal
	{
		private const float PlaneOffset = 0.001f;

		public readonly Vector3[] Corners;

		public readonly Bounds Bounds;

		public readonly TileContents NextTile;

		private readonly Plane _plane;

		public Portal(Doorway doorway, bool useTileBounds, TileContents nextTile)
		{
			//IL_0013: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_005a: 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_00e7: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: 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_0180: 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_018f: 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_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: 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_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)doorway).transform;
			float num = doorway.Socket.Size.x / 2f;
			float y = doorway.Socket.Size.y;
			if (useTileBounds)
			{
				Bounds val = UnityUtil.InverseTransformBounds(transform, doorway.Tile.Bounds);
				num = Mathf.Min(0f - ((Bounds)(ref val)).min.x, ((Bounds)(ref val)).max.x);
				y = ((Bounds)(ref val)).max.y;
			}
			Corners = (Vector3[])(object)new Vector3[4]
			{
				new Vector3(num, 0f, 0f),
				new Vector3(num, y, 0f),
				new Vector3(0f - num, y, 0f),
				new Vector3(0f - num, 0f, 0f)
			};
			for (int i = 0; i < Corners.Length; i++)
			{
				Corners[i] = transform.position + transform.rotation * Corners[i];
			}
			Vector3 val2 = Corners[0];
			Vector3 val3 = Corners[0];
			for (int j = 1; j < Corners.Length; j++)
			{
				Vector3 val4 = Corners[j];
				val2 = Vector3.Min(val2, val4);
				val3 = Vector3.Max(val3, val4);
			}
			Bounds bounds = default(Bounds);
			((Bounds)(ref bounds)).min = val2;
			((Bounds)(ref bounds)).max = val3;
			Bounds = bounds;
			NextTile = nextTile;
			_plane = new Plane(Corners[0], Corners[1], Corners[2]);
			ref readonly Plane plane = ref _plane;
			((Plane)(ref plane)).distance = ((Plane)(ref plane)).distance - 0.001f;
		}

		internal void GetFrustumPlanesNonAlloc(Vector3 origin, Plane[] planes)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			planes[0] = new Plane(Corners[0], Corners[1], origin);
			planes[1] = new Plane(Corners[1], Corners[2], origin);
			planes[2] = new Plane(Corners[2], Corners[3], origin);
			planes[3] = new Plane(Corners[3], Corners[0], origin);
			planes[4] = _plane;
		}

		internal Plane[] GetFrustumPlanes(Vector3 origin)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			Plane[] array = (Plane[])(object)new Plane[5];
			GetFrustumPlanesNonAlloc(origin, array);
			return array;
		}
	}
	public sealed class TileContents
	{
		public readonly Tile tile;

		public readonly Bounds bounds;

		public Portal[] portals;

		public Renderer[] renderers;

		public readonly Light[] lights;

		public Renderer[] externalRenderers = Array.Empty<Renderer>();

		public Light[] externalLights = Array.Empty<Light>();

		public Plane[][] externalLightLinesOfSight = Array.Empty<Plane[]>();

		private static bool _warnedNullObject;

		public TileContents(Tile tile)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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)
			this.tile = tile;
			if (tile.OverrideAutomaticTileBounds)
			{
				bounds = UnityUtil.CondenseBounds(tile.Bounds, (IEnumerable<Doorway>)((Component)tile).GetComponentsInChildren<Doorway>());
			}
			else
			{
				bounds = UnityUtil.TransformBounds(((Component)tile).transform.parent, tile.Placement.Bounds);
			}
			List<Renderer> list = new List<Renderer>(((Component)tile).GetComponentsInChildren<Renderer>(true));
			List<Light> list2 = new List<Light>(((Component)tile).GetComponentsInChildren<Light>(true));
			foreach (Doorway usedDoorway in tile.UsedDoorways)
			{
				if (!((Object)(object)usedDoorway.doorComponent == (Object)null))
				{
					list.AddRange(((Component)usedDoorway).GetComponentsInChildren<Renderer>(true));
					list2.AddRange(((Component)usedDoorway).GetComponentsInChildren<Light>(true));
				}
			}
			int num = 0;
			Renderer[] array = (Renderer[])(object)new Renderer[list.Count];
			foreach (Renderer item in list)
			{
				array[num] = item;
				num++;
			}
			renderers = array;
			num = 0;
			Light[] array2 = (Light[])(object)new Light[list2.Count];
			foreach (Light item2 in list2)
			{
				array2[num] = item2;
				num++;
			}
			lights = array2;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private bool IsInvalid(Component obj)
		{
			if ((Object)(object)obj == (Object)null)
			{
				if (!_warnedNullObject)
				{
					Plugin.LogWarning("A " + ((object)obj).GetType().Name + " in " + ((Object)tile).name + " was unexpectedly destroyed.");
				}
				_warnedNullObject = true;
				return true;
			}
			return false;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private void SetVisible(Renderer[] renderers, bool visible)
		{
			foreach (Renderer val in renderers)
			{
				if (!IsInvalid((Component)(object)val))
				{
					val.forceRenderingOff = !visible;
				}
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private void SetVisible(Light[] lights, bool visible)
		{
			int num = lights.Length;
			for (int i = 0; i < num; i++)
			{
				Light val = lights[i];
				if (!IsInvalid((Component)(object)val))
				{
					val.SetVisible(visible);
				}
			}
		}

		public void SetRenderersVisible(bool visible)
		{
			SetVisible(renderers, visible);
		}

		public void SetLightsVisible(bool visible)
		{
			SetVisible(lights, visible);
		}

		public void SetSelfVisible(bool visible)
		{
			SetRenderersVisible(visible);
			SetLightsVisible(visible);
		}

		public void SetExternalInfluencesVisible(bool visible)
		{
			SetVisible(externalRenderers, visible);
			SetVisible(externalLights, visible);
		}

		public override string ToString()
		{
			if ((Object)(object)tile == (Object)null)
			{
				return "Destroyed";
			}
			return ((Object)tile).name;
		}
	}
}
namespace CullFactory.Behaviours.Visualization
{
	internal class CullingVisualizer : MonoBehaviour
	{
		private const float TileBoundsInset = 0.00025f;

		private static readonly Color[] ColorRotation = (Color[])(object)new Color[6]
		{
			Color.red,
			Color.yellow,
			Color.green,
			Color.blue,
			Color.cyan,
			Color.grey
		};

		private GameObject _portalVisualizersRoot;

		private GameObject _tileBoundsVisualizersRoot;

		private void OnEnable()
		{
			RefreshVisualizers();
		}

		public void RefreshVisualizers()
		{
			SpawnPortalVisualizers();
			SpawnTileBoundsVisualizers();
		}

		private void SpawnPortalVisualizer(Transform prefab, Doorway doorway)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			Transform obj = Object.Instantiate<Transform>(prefab, _portalVisualizersRoot.transform);
			obj.position = ((Component)doorway).transform.position;
			obj.rotation = ((Component)doorway).transform.rotation;
			obj.localScale = new Vector3(doorway.Socket.Size.x, doorway.Socket.Size.y, 1f);
		}

		private void SpawnPortalVisualizers()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			Object.Destroy((Object)(object)_portalVisualizersRoot);
			if (!Config.VisualizePortals.Value)
			{
				return;
			}
			_portalVisualizersRoot = new GameObject("PortalVisualizers");
			Transform val = CreatePortalVisualizer();
			foreach (DoorwayConnection connection in RoundManager.Instance.dungeonGenerator.Generator.CurrentDungeon.Connections)
			{
				SpawnPortalVisualizer(val, connection.A);
				SpawnPortalVisualizer(val, connection.B);
			}
			Object.Destroy((Object)(object)((Component)val).gameObject);
		}

		private void SpawnTileBoundsVisualizers()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			Object.Destroy((Object)(object)_tileBoundsVisualizersRoot);
			if (Config.VisualizeTileBounds.Value)
			{
				_tileBoundsVisualizersRoot = new GameObject("TileBoundsVisualizers");
				Renderer val = CreateTileBoundsVisualizer();
				Vector3 val2 = default(Vector3);
				((Vector3)(ref val2))..ctor(0.00025f, 0.00025f, 0.00025f);
				for (int i = 0; i < DungeonCullingInfo.AllTileContents.Length; i++)
				{
					TileContents tileContents = DungeonCullingInfo.AllTileContents[i];
					Renderer obj = Object.Instantiate<Renderer>(val, _tileBoundsVisualizersRoot.transform);
					Transform transform = ((Component)obj).transform;
					Bounds bounds = tileContents.bounds;
					transform.position = ((Bounds)(ref bounds)).center;
					Transform transform2 = ((Component)obj).transform;
					bounds = tileContents.bounds;
					transform2.localScale = ((Bounds)(ref bounds)).size - val2;
					obj.material.color = ColorRotation[i % ColorRotation.Length];
				}
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
		}

		private static Transform CreatePortalVisualizer()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.CreatePrimitive((PrimitiveType)5);
			((Object)val).name = "PortalVisualizer";
			Object.DestroyImmediate((Object)(object)val.GetComponent<Collider>());
			Renderer component = val.GetComponent<Renderer>();
			component.material = new Material(Shader.Find("HDRP/Unlit"))
			{
				name = "PortalVisualizerMaterial",
				color = Color.white
			};
			component.shadowCastingMode = (ShadowCastingMode)0;
			Mesh mesh = val.GetComponent<MeshFilter>().mesh;
			Vector3[] vertices = mesh.vertices;
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(0f, 0.5f, 0f - Config.VisualizedPortalOutsetDistance.Value);
			for (int i = 0; i < vertices.Length; i++)
			{
				ref Vector3 reference = ref vertices[i];
				reference += val2;
			}
			mesh.vertices = vertices;
			mesh.RecalculateBounds();
			return val.transform;
		}

		private static Renderer CreateTileBoundsVisualizer()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3);
			((Object)obj).name = "TileBounds";
			Object.DestroyImmediate((Object)(object)obj.GetComponent<Collider>());
			Renderer component = obj.GetComponent<Renderer>();
			component.material = new Material(Shader.Find("HDRP/Unlit"))
			{
				name = "TileBoundsVisualizerMaterial",
				color = Color.yellow
			};
			component.shadowCastingMode = (ShadowCastingMode)0;
			Mesh sharedMesh = obj.GetComponent<MeshFilter>().sharedMesh;
			Mesh val = sharedMesh;
			List<int> list = new List<int>();
			int[] triangles = sharedMesh.triangles;
			foreach (int item in triangles)
			{
				list.Add(item);
			}
			foreach (int item2 in sharedMesh.triangles.Reverse())
			{
				list.Add(item2);
			}
			val.triangles = list.ToArray();
			return component;
		}

		private void OnDisable()
		{
			Object.Destroy((Object)(object)_portalVisualizersRoot);
			Object.Destroy((Object)(object)_tileBoundsVisualizersRoot);
		}
	}
}
namespace CullFactory.Behaviours.CullingMethods
{
	public abstract class CullingMethod : MonoBehaviour
	{
		public struct VisibilitySets
		{
			public readonly HashSet<TileContents> directTiles;

			public readonly HashSet<TileContents> indirectTiles;

			public readonly HashSet<GrabbableObjectContents> items;

			public readonly HashSet<Light> dynamicLights;

			public VisibilitySets()
			{
				directTiles = new HashSet<TileContents>();
				indirectTiles = new HashSet<TileContents>();
				items = new HashSet<GrabbableObjectContents>();
				dynamicLights = new HashSet<Light>();
			}

			public void ClearAll()
			{
				directTiles.Clear();
				indirectTiles.Clear();
				items.Clear();
				dynamicLights.Clear();
			}
		}

		public const float ExtraShadowFadeDistance = 1.1111112f;

		protected Camera _hudCamera;

		protected bool _benchmarking;

		protected long _totalCalls;

		private float _updateInterval;

		private float _lastUpdateTime;

		private VisibilitySets _visibility = new VisibilitySets();

		private VisibilitySets _visibilityLastCall = new VisibilitySets();

		private float[] _lightShadowFadeDistances;

		protected TileContents _debugTile;

		private double _cullingTime;

		public static CullingMethod Instance { get; private set; }

		public static void Initialize()
		{
			if ((Object)(object)Instance != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)Instance);
				Instance = null;
			}
			if ((Object)(object)RoundManager.Instance == (Object)null || (Object)(object)RoundManager.Instance.dungeonGenerator == (Object)null)
			{
				return;
			}
			DungeonGenerator generator = RoundManager.Instance.dungeonGenerator.Generator;
			GameObject gameObject = ((Component)generator.CurrentDungeon).gameObject;
			CullingMethod cullingMethod = null;
			switch (Config.GetCullingType(generator.DungeonFlow))
			{
			case CullingType.PortalOcclusionCulling:
				cullingMethod = gameObject.AddComponent<PortalOcclusionCuller>();
				break;
			case CullingType.DepthCulling:
				cullingMethod = gameObject.AddComponent<DepthCuller>();
				break;
			default:
				throw new ArgumentOutOfRangeException();
			case CullingType.None:
				break;
			}
			if (!((Object)(object)cullingMethod == (Object)null))
			{
				if (Config.UpdateFrequency.Value > 0f)
				{
					cullingMethod._updateInterval = 1f / Config.UpdateFrequency.Value;
				}
				else
				{
					cullingMethod._updateInterval = 0f;
				}
			}
		}

		private void Awake()
		{
			Instance = this;
			_hudCamera = GameObject.Find("Systems/UI/UICamera").GetComponent<Camera>();
		}

		private void OnEnable()
		{
			DungeonCullingInfo.AllTileContents.SetSelfVisible(visible: false);
			DynamicObjects.AllGrabbableObjectContentsOutside.SetVisible(visible: false);
			DynamicObjects.AllGrabbableObjectContentsInInterior.SetVisible(visible: false);
			((IEnumerable<Light>)DynamicObjects.AllLightsOutside).SetVisible(visible: false);
			((IEnumerable<Light>)DynamicObjects.AllLightsInInterior).SetVisible(visible: false);
			DisableShadowDistanceFading();
			RenderPipelineManager.beginContextRendering += DoCulling;
		}

		private void DisableShadowDistanceFading()
		{
			if (!Config.DisableShadowDistanceFading.Value)
			{
				return;
			}
			_lightShadowFadeDistances = new float[DungeonCullingInfo.AllLightsInDungeon.Length];
			for (int i = 0; i < _lightShadowFadeDistances.Length; i++)
			{
				Light val = DungeonCullingInfo.AllLightsInDungeon[i];
				if (!((Object)(object)val == (Object)null))
				{
					HDAdditionalLightData component = ((Component)val).GetComponent<HDAdditionalLightData>();
					if (!((Object)(object)component == (Object)null))
					{
						_lightShadowFadeDistances[i] = component.shadowFadeDistance;
						component.shadowFadeDistance = component.fadeDistance * 1.1111112f;
					}
				}
			}
		}

		internal void OnDynamicLightsCollected()
		{
			((IEnumerable<Light>)DynamicObjects.AllLightsOutside).SetVisible(visible: false);
			((IEnumerable<Light>)DynamicObjects.AllLightsInInterior).SetVisible(visible: false);
			((IEnumerable<Light>)_visibilityLastCall.dynamicLights).SetVisible(visible: true);
		}

		internal void OnItemCreatedOrChanged(GrabbableObjectContents item)
		{
			item.SetVisible(_visibilityLastCall.items.Contains(item));
		}

		protected virtual void BenchmarkEnded()
		{
			double num = _cullingTime / (double)_totalCalls;
			Plugin.Log($"Total culling time {num * 1000000.0:0.####} microseconds.");
			_cullingTime = 0.0;
		}

		private void Update()
		{
			if (Config.Logging.Value && UnityInput.Current.GetKey("LeftAlt") && UnityInput.Current.GetKeyUp("B"))
			{
				_benchmarking = !_benchmarking;
				if (!_benchmarking)
				{
					BenchmarkEnded();
					_totalCalls = 0L;
				}
			}
		}

		protected abstract void AddVisibleObjects(List<Camera> cameras, VisibilitySets visibility);

		protected void AddAllObjectsWithinOrthographicCamera(Camera camera, VisibilitySets visibility)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			Plane[] array = GeometryUtility.CalculateFrustumPlanes(camera);
			TileContents[] allTileContents = DungeonCullingInfo.AllTileContents;
			foreach (TileContents tileContents in allTileContents)
			{
				if (GeometryUtility.TestPlanesAABB(array, tileContents.bounds))
				{
					visibility.directTiles.Add(tileContents);
				}
			}
			foreach (GrabbableObjectContents item in DynamicObjects.AllGrabbableObjectContentsInInterior)
			{
				if (item.IsVisible(array))
				{
					visibility.items.Add(item);
				}
			}
			foreach (GrabbableObjectContents item2 in DynamicObjects.AllGrabbableObjectContentsOutside)
			{
				if (item2.IsVisible(array))
				{
					visibility.items.Add(item2);
				}
			}
			visibility.dynamicLights.UnionWith(DynamicObjects.AllLightsOutside);
			foreach (Light item3 in DynamicObjects.AllLightsInInterior)
			{
				if (!((Object)(object)item3 == (Object)null) && item3.Affects((IEnumerable<TileContents>)_visibility.directTiles))
				{
					visibility.dynamicLights.Add(item3);
				}
			}
		}

		private void DoCulling(ScriptableRenderContext context, List<Camera> cameras)
		{
			bool flag = false;
			foreach (Camera camera in cameras)
			{
				if (camera != _hudCamera && !(((Object)camera).name == "UE_Freecam") && !(((Object)camera).name == "SceneCamera"))
				{
					flag = true;
				}
			}
			if (!flag || Time.time - _lastUpdateTime < _updateInterval)
			{
				return;
			}
			double realtimeSinceStartupAsDouble = Time.realtimeSinceStartupAsDouble;
			_lastUpdateTime = Time.time;
			_visibility.ClearAll();
			_debugTile = null;
			AddVisibleObjects(cameras, _visibility);
			foreach (TileContents directTile in _visibilityLastCall.directTiles)
			{
				if (!_visibility.directTiles.Contains(directTile))
				{
					directTile.SetSelfVisible(visible: false);
					directTile.SetExternalInfluencesVisible(visible: false);
				}
			}
			foreach (TileContents indirectTile in _visibilityLastCall.indirectTiles)
			{
				if (!_visibility.indirectTiles.Contains(indirectTile))
				{
					indirectTile.SetRenderersVisible(visible: false);
				}
			}
			foreach (TileContents directTile2 in _visibility.directTiles)
			{
				directTile2.SetSelfVisible(visible: true);
				directTile2.SetExternalInfluencesVisible(visible: true);
			}
			foreach (TileContents indirectTile2 in _visibility.indirectTiles)
			{
				indirectTile2.SetRenderersVisible(visible: true);
			}
			foreach (GrabbableObjectContents item in _visibilityLastCall.items)
			{
				if (!_visibility.items.Contains(item))
				{
					item.SetVisible(visible: false);
				}
			}
			foreach (GrabbableObjectContents item2 in _visibility.items)
			{
				if (!_visibilityLastCall.items.Contains(item2))
				{
					item2.SetVisible(visible: true);
				}
			}
			foreach (Light dynamicLight in _visibilityLastCall.dynamicLights)
			{
				if ((Object)(object)dynamicLight != (Object)null && !_visibility.dynamicLights.Contains(dynamicLight))
				{
					dynamicLight.SetVisible(visible: false);
				}
			}
			foreach (Light dynamicLight2 in _visibility.dynamicLights)
			{
				if ((Object)(object)dynamicLight2 != (Object)null && !_visibilityLastCall.dynamicLights.Contains(dynamicLight2))
				{
					dynamicLight2.SetVisible(visible: true);
				}
			}
			VisibilitySets visibility = _visibility;
			VisibilitySets visibilityLastCall = _visibilityLastCall;
			_visibilityLastCall = visibility;
			_visibility = visibilityLastCall;
			if (_benchmarking)
			{
				_totalCalls++;
				_cullingTime += Time.realtimeSinceStartupAsDouble - realtimeSinceStartupAsDouble;
			}
		}

		private void OnDisable()
		{
			DungeonCullingInfo.AllTileContents.SetSelfVisible(visible: true);
			DynamicObjects.AllGrabbableObjectContentsOutside.SetVisible(visible: true);
			DynamicObjects.AllGrabbableObjectContentsInInterior.SetVisible(visible: true);
			((IEnumerable<Light>)DynamicObjects.AllLightsOutside).SetVisible(visible: true);
			((IEnumerable<Light>)DynamicObjects.AllLightsInInterior).SetVisible(visible: true);
			_visibilityLastCall.ClearAll();
			RestoreShadowDistanceFading();
			RenderPipelineManager.beginContextRendering -= DoCulling;
		}

		private void OnDestroy()
		{
			Instance = null;
		}

		private void RestoreShadowDistanceFading()
		{
			if (_lightShadowFadeDistances == null)
			{
				return;
			}
			for (int i = 0; i < _lightShadowFadeDistances.Length; i++)
			{
				Light val = DungeonCullingInfo.AllLightsInDungeon[i];
				if (!((Object)(object)val == (Object)null))
				{
					HDAdditionalLightData component = ((Component)val).GetComponent<HDAdditionalLightData>();
					if (!((Object)(object)component == (Object)null))
					{
						component.shadowFadeDistance = _lightShadowFadeDistances[i];
					}
				}
			}
			_lightShadowFadeDistances = null;
		}

		private void OnDrawGizmos()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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)
			if (_debugTile != null)
			{
				Gizmos.color = Color.green;
				TileContents debugTile = _debugTile;
				Bounds bounds = debugTile.bounds;
				Vector3 center = ((Bounds)(ref bounds)).center;
				bounds = debugTile.bounds;
				Gizmos.DrawWireCube(center, ((Bounds)(ref bounds)).size);
				Gizmos.color = Color.green;
				Renderer[] renderers = debugTile.renderers;
				for (int i = 0; i < renderers.Length; i++)
				{
					Bounds bounds2 = renderers[i].bounds;
					Gizmos.DrawWireCube(((Bounds)(ref bounds2)).center, ((Bounds)(ref bounds2)).size);
				}
				Light[] lights = debugTile.lights;
				foreach (Light val in lights)
				{
					Gizmos.DrawWireSphere(((Component)val).transform.position, val.range);
				}
				Gizmos.color = Color.blue;
				lights = debugTile.externalLights;
				foreach (Light val2 in lights)
				{
					Gizmos.DrawWireSphere(((Component)val2).transform.position, val2.range);
				}
				renderers = debugTile.externalRenderers;
				for (int i = 0; i < renderers.Length; i++)
				{
					Bounds bounds3 = renderers[i].bounds;
					Gizmos.DrawWireCube(((Bounds)(ref bounds3)).center, ((Bounds)(ref bounds3)).size);
				}
			}
		}
	}
	public sealed class DepthCuller : CullingMethod
	{
		protected override void AddVisibleObjects(List<Camera> cameras, VisibilitySets visibility)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			foreach (Camera camera in cameras)
			{
				if (camera.orthographic)
				{
					AddAllObjectsWithinOrthographicCamera(camera, visibility);
					continue;
				}
				TileContents tileContents = ((Component)camera).transform.position.GetTileContents();
				if (tileContents == null)
				{
					visibility.items.UnionWith(DynamicObjects.AllGrabbableObjectContentsOutside);
					visibility.dynamicLights.UnionWith(DynamicObjects.AllLightsOutside);
					continue;
				}
				if (_debugTile == null)
				{
					_debugTile = tileContents;
				}
				IncludeNearbyTiles(tileContents.tile, visibility.directTiles);
				foreach (GrabbableObjectContents item in DynamicObjects.AllGrabbableObjectContentsInInterior)
				{
					item.CalculateBounds();
					if (item.IsWithin((IEnumerable<TileContents>)visibility.directTiles))
					{
						visibility.items.Add(item);
					}
				}
				foreach (Light item2 in DynamicObjects.AllLightsInInterior)
				{
					if (!((Object)(object)item2 == (Object)null) && item2.Affects((IEnumerable<TileContents>)visibility.directTiles))
					{
						visibility.dynamicLights.Add(item2);
					}
				}
			}
		}

		private void IncludeNearbyTiles(Tile origin, HashSet<TileContents> visibleTiles)
		{
			int num = Config.MaxBranchingDepth.Value - 1;
			Stack<TileDepthTester> stack = new Stack<TileDepthTester>(num * num);
			HashSet<Tile> hashSet = new HashSet<Tile>();
			stack.Clear();
			stack.Push(new TileDepthTester(origin, 0));
			while (stack.Count > 0)
			{
				TileDepthTester tileDepthTester = stack.Pop();
				visibleTiles.Add(DungeonCullingInfo.TileContentsForTile[tileDepthTester.tile]);
				hashSet.Add(tileDepthTester.tile);
				if (tileDepthTester.iteration == num)
				{
					continue;
				}
				foreach (Doorway usedDoorway in tileDepthTester.tile.UsedDoorways)
				{
					Tile tile = usedDoorway.ConnectedDoorway.Tile;
					if (!hashSet.Contains(tile))
					{
						stack.Push(new TileDepthTester(tile, tileDepthTester.iteration + 1));
					}
				}
			}
		}
	}
	internal readonly struct TileDepthTester
	{
		public readonly Tile tile;

		public readonly int iteration;

		public TileDepthTester(Tile tile, int iteration)
		{
			this.tile = tile;
			this.iteration = iteration;
		}
	}
	public sealed class PortalOcclusionCuller : CullingMethod
	{
		private double _camerasTime;

		private double _visibilityTime;

		private double _itemBoundsTime;

		private double _itemShadowsTime;

		private double _dynamicLightsLineOfSightTime;

		private double _dynamicLightsTime;

		private readonly HashSet<TileContents> _dynamicLightOccludingTiles = new HashSet<TileContents>();

		protected override void BenchmarkEnded()
		{
			base.BenchmarkEnded();
			double num = _camerasTime / (double)_totalCalls;
			double num2 = _visibilityTime / (double)_totalCalls;
			double num3 = _itemBoundsTime / (double)_totalCalls;
			double num4 = _itemShadowsTime / (double)_totalCalls;
			double num5 = _dynamicLightsLineOfSightTime / (double)_totalCalls;
			double num6 = _dynamicLightsTime / (double)_totalCalls;
			double num7 = num + num4 + num6;
			Plugin.Log($"Total portal occlusion culling time {num7 * 1000000.0:0.####} microseconds.\n" + $"    Cameras took {num * 1000000.0:0.####} microseconds.\n" + $"    Direct visibility testing took {num2 * 1000000.0:0.####} microseconds.\n" + $"    Calculating item bounds took {num3 * 1000000.0:0.####} microseconds.\n" + $"    Dynamic lights line of sight checks took {num5 * 1000000.0:0.####} microseconds.\n" + $"    Dynamic light influence checks took {(num6 - num5) * 1000000.0:0.####} microseconds.\n" + $"    Item shadows took {(num4 - num3) * 1000000.0:0.####} microseconds.");
			_camerasTime = 0.0;
			_visibilityTime = 0.0;
			_itemBoundsTime = 0.0;
			_itemShadowsTime = 0.0;
			_dynamicLightsLineOfSightTime = 0.0;
			_dynamicLightsTime = 0.0;
			_totalCalls = 0L;
		}

		private static bool ItemIsVisible(GrabbableObjectContents item, VisibilitySets visibility)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			foreach (TileContents directTile in visibility.directTiles)
			{
				if (item.IsWithin(directTile.bounds))
				{
					return true;
				}
				Plane[][] externalLightLinesOfSight = directTile.externalLightLinesOfSight;
				foreach (Plane[] planes in externalLightLinesOfSight)
				{
					if (item.IsVisible(planes))
					{
						return true;
					}
				}
			}
			foreach (TileContents indirectTile in visibility.indirectTiles)
			{
				if (item.IsWithin(indirectTile.bounds))
				{
					return true;
				}
			}
			return false;
		}

		protected override void AddVisibleObjects(List<Camera> cameras, VisibilitySets visibility)
		{
			//IL_0074: 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_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			double realtimeSinceStartupAsDouble = Time.realtimeSinceStartupAsDouble;
			bool flag = false;
			bool flag2 = false;
			double num = 0.0;
			double num2 = 0.0;
			foreach (Camera camera in cameras)
			{
				if (camera.orthographic)
				{
					AddAllObjectsWithinOrthographicCamera(camera, visibility);
					continue;
				}
				double realtimeSinceStartupAsDouble2 = Time.realtimeSinceStartupAsDouble;
				Vector3 position = ((Component)camera).transform.position;
				num += Time.realtimeSinceStartupAsDouble - realtimeSinceStartupAsDouble2;
				TileContents tileContents = position.GetTileContents();
				if (tileContents != null)
				{
					flag = true;
					if (_debugTile == null)
					{
						_debugTile = tileContents;
					}
					double realtimeSinceStartupAsDouble3 = Time.realtimeSinceStartupAsDouble;
					VisibilityTesting.CallForEachLineOfSight(camera, tileContents, delegate(TileContents[] tiles, Plane[][] frustums, int index)
					{
						visibility.directTiles.Add(tiles[index]);
					});
					num2 += Time.realtimeSinceStartupAsDouble - realtimeSinceStartupAsDouble3;
				}
				else if (!flag2)
				{
					visibility.items.UnionWith(DynamicObjects.AllGrabbableObjectContentsOutside);
					visibility.dynamicLights.UnionWith(DynamicObjects.AllLightsOutside);
					flag2 = true;
				}
			}
			double num3 = Time.realtimeSinceStartupAsDouble - realtimeSinceStartupAsDouble;
			if (!flag)
			{
				return;
			}
			double realtimeSinceStartupAsDouble4 = Time.realtimeSinceStartupAsDouble;
			double num4 = 0.0;
			foreach (Light item2 in DynamicObjects.AllLightsInInterior)
			{
				if ((Object)(object)item2 == (Object)null || !((Behaviour)item2).isActiveAndEnabled || !item2.Affects((IEnumerable<TileContents>)visibility.directTiles))
				{
					continue;
				}
				bool flag3 = item2.PassesThroughOccluders();
				if (flag3)
				{
					visibility.dynamicLights.Add(item2);
				}
				if (!item2.HasShadows())
				{
					continue;
				}
				Vector3 position2 = (