Decompiled source of LabyrinthianFacilities v0.7.1

LabyrinthianFacilities.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BoundsExtensions;
using DunGen;
using DunGen.Graph;
using HarmonyLib;
using LabyrinthianFacilities.Compatibility;
using LabyrinthianFacilities.NetcodePatcher;
using LabyrinthianFacilities.Patches;
using LabyrinthianFacilities.Serialization;
using LabyrinthianFacilities.Util;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.AI.Navigation;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LabyrinthianFacilities")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LabyrinthianFacilities")]
[assembly: AssemblyTitle("LabyrinthianFacilities")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
[module: NetcodePatchedAssembly]
internal class <Module>
{
	static <Module>()
	{
	}
}
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 LabyrinthianFacilities
{
	public class Config
	{
		internal static ConfigFile ConfigFile;

		private static Config singleton;

		private ConfigEntry<bool> m_GlobalEnable;

		private ConfigEntry<bool> m_EnableNoncollectionPenalty;

		private ConfigEntry<bool> m_ExcludeCruiserScrap;

		private ConfigEntry<bool> m_ExcludeSurfaceScrap;

		private ConfigEntry<bool> m_ExcludeHive;

		private ConfigEntry<bool> m_SaveGrabbableMapObjects;

		private ConfigEntry<bool> m_SaveEquipment;

		private ConfigEntry<bool> m_SaveScrap;

		private ConfigEntry<bool> m_SaveHives;

		private ConfigEntry<bool> m_SaveCruisers;

		private ConfigEntry<bool> m_SaveHazards;

		private ConfigEntry<bool> m_SaveTurrets;

		private ConfigEntry<bool> m_SaveLandmines;

		private ConfigEntry<bool> m_SaveSpikeTraps;

		private ConfigEntry<bool> m_UseCustomGeneration;

		private ConfigEntry<bool> m_SaveMaps;

		private ConfigEntry<float> m_MinimumTileMultiplier;

		private ConfigEntry<float> m_MaximumTileMultiplier;

		private ConfigEntry<float> m_LowerIterationMultiplier;

		private ConfigEntry<float> m_UpperIterationMultiplier;

		private ConfigEntry<bool> m_BouncyCruisers;

		private ConfigEntry<bool> m_ForbiddenPassages;

		private ConfigEntry<LogLevel> m_LogLevels;

		private ConfigEntry<bool> m_EnableVerboseGeneration;

		private ConfigEntry<bool> m_EnableVerboseSerialization;

		private ConfigEntry<bool> m_EnableVerboseDeserialization;

		private ConfigEntry<bool> m_EnableHistory;

		private ConfigEntry<bool> m_UseSetSeed;

		private ConfigEntry<int> m_Seed;

		private ConfigEntry<bool> m_IncrementSetSeed;

		public static Config Singleton => singleton ?? (singleton = new Config());

		public bool GlobalEnable { get; set; }

		public bool EnableNoncollectionPenalty { get; set; }

		public bool ExcludeCruiserScrap { get; set; }

		public bool ExcludeSurfaceScrap { get; set; }

		public bool ExcludeHive { get; set; }

		public bool SaveGrabbableMapObjects { get; set; }

		public bool SaveEquipment { get; set; }

		public bool SaveScrap { get; set; }

		public bool SaveHives { get; set; }

		public bool SaveCruisers { get; set; }

		public bool SaveHazards { get; set; }

		public bool SaveTurrets { get; set; }

		public bool SaveLandmines { get; set; }

		public bool SaveSpikeTraps { get; set; }

		public bool UseCustomGeneration { get; set; }

		public bool SaveMaps { get; set; }

		public float MinimumTileMultiplier { get; set; }

		public float MaximumTileMultiplier { get; set; }

		public float LowerIterationMultiplier { get; set; }

		public float UpperIterationMultiplier { get; set; }

		public bool BouncyCruisers { get; set; }

		public bool ForbiddenPassages { get; set; }

		public LogLevel LogLevels { get; set; }

		public bool EnableVerboseGeneration { get; set; }

		public bool EnableVerboseSerialization { get; set; }

		public bool EnableVerboseDeserialization { get; set; }

		public bool EnableHistory { get; set; }

		public bool UseSetSeed { get; set; }

		public int Seed { get; set; }

		public bool IncrementSetSeed { get; set; }

		public Config()
		{
			if (singleton != null)
			{
				throw new InvalidOperationException("Singleton violation");
			}
			singleton = this;
			ConfigFile configFile = ConfigFile;
			configFile.SaveOnConfigSet = false;
			string text = "Features";
			m_GlobalEnable = configFile.Bind<bool>(text, "GlobalEnable", true, "Enables the mod. Set this to false if you want to hurt my feelings. ");
			text = "Features.NoncollectionPenalty";
			m_EnableNoncollectionPenalty = configFile.Bind<bool>(text, "EnableNoncollectionPenalty", true, "NOT YET IMPLEMENTED; Generates less scrap the next day if there is already scrap from days prior. ");
			m_ExcludeSurfaceScrap = configFile.Bind<bool>(text, "ExcludeSurfaceScrap", false, "NOT YET IMPLEMENTED; Exclude scrap at the surface when considering noncollection penalty\n(Requires EnableNoncollectionPenalty)");
			m_ExcludeCruiserScrap = configFile.Bind<bool>(text, "ExcludeCruiserScrap", false, "NOT YET IMPLEMENTED; Exclude scrap in cruisers when considering noncollection penalty\n(Requires EnableNoncollectionPenalty)");
			m_ExcludeHive = configFile.Bind<bool>(text, "ExcludeHive", true, "NOT YET IMPLEMENTED; Exclude beehives when considering noncollection penalty\n(Requires EnableNoncollectionPenalty)");
			text = "Features.MapObjects";
			m_SaveGrabbableMapObjects = configFile.Bind<bool>(text, "SaveGrabbableMapObjects", true, "Save 'GrabbableMapObjects' (basically scrap & equipment)");
			m_SaveEquipment = configFile.Bind<bool>(text, "SaveEquipment", true, "Save Equipment (Requires SaveGrabbableMapObjects)");
			m_SaveScrap = configFile.Bind<bool>(text, "SaveScrap", true, "Save Scrap (Requires SaveGrabbableMapObjects)");
			m_SaveHives = configFile.Bind<bool>(text, "SaveHives", true, "Save Beehives (Requires SaveGrabbableMapObjects)");
			m_SaveCruisers = configFile.Bind<bool>(text, "SaveCruisers", true, "Save Cruisers");
			text = "Features.Hazards";
			m_SaveHazards = configFile.Bind<bool>(text, "SaveHazards", false, "Save Hazards (turrets, landmines, etc.)");
			m_SaveTurrets = configFile.Bind<bool>(text, "SaveTurrets", true, "Save Turrets (Requires SaveHazards)");
			m_SaveLandmines = configFile.Bind<bool>(text, "SaveLandmines", true, "Save Landmines (Requires SaveHazards)");
			m_SaveSpikeTraps = configFile.Bind<bool>(text, "SaveSpikeTraps", true, "Save Spike Traps (Requires SaveHazards)");
			text = "Features.InteriorGeneration";
			m_UseCustomGeneration = configFile.Bind<bool>(text, "UseCustomGeneration", true, "Use Custom Generation");
			m_SaveMaps = configFile.Bind<bool>(text, "SaveMaps", true, "Save interiors (Requires UseCustomGeneration)");
			m_MinimumTileMultiplier = configFile.Bind<float>(text, "MinimumTileMultiplier", 2.5f, "Multiplier for the minimum amount of tiles. Multiplies by the average amount of main tiles that would be generated by DunGen. (Requires UseCustomGeneration)");
			m_MaximumTileMultiplier = configFile.Bind<float>(text, "MaximumTileMultiplier", 6f, "Multiplier for the maximum amount of tiles. Multiplies by the average amount of main tiles that would be generated by DunGen. (Requires UseCustomGeneration)");
			m_LowerIterationMultiplier = configFile.Bind<float>(text, "LowerIterationMultiplier", 1f, "Multiplier for the minimum amount of tiles to generate in a single day. Multiplies by the the result of MinimumTileMultiplier's multiplication. (Requires UseCustomGeneration)");
			m_UpperIterationMultiplier = configFile.Bind<float>(text, "UpperIterationMultiplier", 1.5f, "Multiplier for the maximum amount of tiles to generate in a single day. Multiplies by the the result of *Minimum*TileMultiplier's multiplication. (Requires UseCustomGeneration)");
			text = "Features.EasterEggs";
			m_BouncyCruisers = configFile.Bind<bool>(text, "BouncyCruisers", false, "The magic word is '" + EasterEggDetection.cruiserMagicWord + "'");
			m_ForbiddenPassages = configFile.Bind<bool>(text, "ForbiddenPassages", false, "...?");
			text = "Debug.Logging";
			m_LogLevels = configFile.Bind<LogLevel>(text, "LogLevels", (LogLevel)63, "Which log levels to show in the console");
			m_EnableVerboseGeneration = configFile.Bind<bool>(text, "EnableVerboseGeneration", false, "Enables verbose logging for generation\n(Requires LogLevels contains Debug)");
			m_EnableVerboseSerialization = configFile.Bind<bool>(text, "EnableVerboseSerialization", false, "Enables verbose logging for serialization (used for saving maps & sending data to clients)\n(Requires LogLevels contains Debug)");
			m_EnableVerboseDeserialization = configFile.Bind<bool>(text, "EnableVerboseDeserialization", false, "Enables verbose logging for deserialization (used for loading maps & receiving data from server)\n(Requires LogLevels contains Debug)");
			text = "Debug.History";
			m_EnableHistory = configFile.Bind<bool>(text, "EnableHistory", true, "Enables recording of seeds, interiors, and moons each day, for each save. Located in the same place as savedata. ");
			text = "Features.SetSeed";
			m_UseSetSeed = configFile.Bind<bool>(text, "UseSetSeed", false, "Enables the set seed\n(The set seed only affects tile generation; it does not affect weather, sales, or which interior is chosen)");
			m_Seed = configFile.Bind<int>(text, "Seed", 0, "The seed to use for set seed");
			m_IncrementSetSeed = configFile.Bind<bool>(text, "IncrementSetSeed", true, "Whether to increment the set seed daily");
			configFile.Save();
			configFile.SaveOnConfigSet = true;
			InitFromConfigFile();
		}

		public void InitFromConfigFile()
		{
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			GlobalEnable = m_GlobalEnable.Value;
			EnableNoncollectionPenalty = m_EnableNoncollectionPenalty.Value;
			ExcludeCruiserScrap = m_ExcludeCruiserScrap.Value;
			ExcludeSurfaceScrap = m_ExcludeSurfaceScrap.Value;
			ExcludeHive = m_ExcludeHive.Value;
			SaveGrabbableMapObjects = m_SaveGrabbableMapObjects.Value;
			SaveEquipment = m_SaveEquipment.Value;
			SaveScrap = m_SaveScrap.Value;
			SaveHives = m_SaveHives.Value;
			SaveCruisers = m_SaveCruisers.Value;
			SaveHazards = m_SaveHazards.Value;
			SaveTurrets = m_SaveTurrets.Value;
			SaveLandmines = m_SaveLandmines.Value;
			SaveSpikeTraps = m_SaveSpikeTraps.Value;
			UseCustomGeneration = m_UseCustomGeneration.Value;
			SaveMaps = m_SaveMaps.Value;
			MinimumTileMultiplier = m_MinimumTileMultiplier.Value;
			MaximumTileMultiplier = m_MaximumTileMultiplier.Value;
			LowerIterationMultiplier = m_LowerIterationMultiplier.Value;
			UpperIterationMultiplier = m_UpperIterationMultiplier.Value;
			BouncyCruisers = m_BouncyCruisers.Value;
			ForbiddenPassages = m_ForbiddenPassages.Value;
			LogLevels = m_LogLevels.Value;
			EnableVerboseGeneration = m_EnableVerboseGeneration.Value;
			EnableVerboseSerialization = m_EnableVerboseSerialization.Value;
			EnableVerboseDeserialization = m_EnableVerboseDeserialization.Value;
			EnableHistory = m_EnableHistory.Value;
			UseSetSeed = m_UseSetSeed.Value;
			Seed = m_Seed.Value;
			IncrementSetSeed = m_IncrementSetSeed.Value;
		}
	}
	public class ConfigNetworkSerializer<T> : Serializer<T> where T : Config
	{
		public override void Serialize(SerializationContext sc, T tgt)
		{
			sc.AddBools(new <>z__ReadOnlyArray<bool>(new bool[21]
			{
				tgt.GlobalEnable, tgt.EnableNoncollectionPenalty, tgt.ExcludeCruiserScrap, tgt.ExcludeSurfaceScrap, tgt.ExcludeHive, tgt.SaveGrabbableMapObjects, tgt.SaveEquipment, tgt.SaveScrap, tgt.SaveHives, tgt.SaveCruisers,
				tgt.SaveHazards, tgt.SaveTurrets, tgt.SaveLandmines, tgt.SaveSpikeTraps, tgt.UseCustomGeneration, tgt.SaveMaps, tgt.BouncyCruisers, tgt.ForbiddenPassages, tgt.EnableHistory, tgt.UseSetSeed,
				tgt.IncrementSetSeed
			}), (bool b) => b);
			sc.Add(tgt.MinimumTileMultiplier);
			sc.Add(tgt.MaximumTileMultiplier);
			sc.Add(tgt.LowerIterationMultiplier);
			sc.Add(tgt.UpperIterationMultiplier);
			sc.Add(tgt.Seed);
		}

		protected override T Deserialize(T rt, DeserializationContext dc)
		{
			IEnumerator<bool> enumerator = dc.ConsumeBools(21uL).GetEnumerator();
			enumerator.MoveNext();
			rt.GlobalEnable = enumerator.Current;
			enumerator.MoveNext();
			rt.EnableNoncollectionPenalty = enumerator.Current;
			enumerator.MoveNext();
			rt.ExcludeCruiserScrap = enumerator.Current;
			enumerator.MoveNext();
			rt.ExcludeSurfaceScrap = enumerator.Current;
			enumerator.MoveNext();
			rt.ExcludeHive = enumerator.Current;
			enumerator.MoveNext();
			rt.SaveGrabbableMapObjects = enumerator.Current;
			enumerator.MoveNext();
			rt.SaveEquipment = enumerator.Current;
			enumerator.MoveNext();
			rt.SaveScrap = enumerator.Current;
			enumerator.MoveNext();
			rt.SaveHives = enumerator.Current;
			enumerator.MoveNext();
			rt.SaveCruisers = enumerator.Current;
			enumerator.MoveNext();
			rt.SaveHazards = enumerator.Current;
			enumerator.MoveNext();
			rt.SaveTurrets = enumerator.Current;
			enumerator.MoveNext();
			rt.SaveLandmines = enumerator.Current;
			enumerator.MoveNext();
			rt.SaveSpikeTraps = enumerator.Current;
			enumerator.MoveNext();
			rt.UseCustomGeneration = enumerator.Current;
			enumerator.MoveNext();
			rt.SaveMaps = enumerator.Current;
			enumerator.MoveNext();
			rt.BouncyCruisers = enumerator.Current;
			enumerator.MoveNext();
			rt.ForbiddenPassages = enumerator.Current;
			enumerator.MoveNext();
			rt.EnableHistory = enumerator.Current;
			enumerator.MoveNext();
			rt.UseSetSeed = enumerator.Current;
			enumerator.MoveNext();
			rt.IncrementSetSeed = enumerator.Current;
			dc.Consume(4).CastInto(out float o);
			rt.MinimumTileMultiplier = o;
			dc.Consume(4).CastInto(out o);
			rt.MaximumTileMultiplier = o;
			dc.Consume(4).CastInto(out o);
			rt.LowerIterationMultiplier = o;
			dc.Consume(4).CastInto(out o);
			rt.UpperIterationMultiplier = o;
			dc.Consume(4).CastInto(out int o2);
			rt.Seed = o2;
			return rt;
		}

		public override T Deserialize(DeserializationContext dc)
		{
			return Deserialize((T)Config.Singleton, dc);
		}
	}
	public interface IDoorwayManager : ICollection<Doorway>, IEnumerable<Doorway>, IEnumerable
	{
		IChoice<Doorway, float> GetLeaves(Func<Doorway, float> weightFunction);

		IChoice<Connection, float> GetPotentialConnections(Func<Connection, float> weightFunction);

		IChoice<Connection, float> GetActiveConnections(Func<Connection, float> weightFunction);
	}
	public class DoorwayManager : IDoorwayManager, ICollection<Doorway>, IEnumerable<Doorway>, IEnumerable
	{
		public enum DoorType
		{
			LEAF,
			ACTIVE_CONNECTOR,
			POTENTIAL_CONNECTOR,
			FALSE_POTENTIAL_CONNECTOR
		}

		protected GameMap map;

		private Dictionary<Doorway, DoorType> doorways;

		private Dictionary<Vector3, Doorway> leaves;

		private HashSet<Connection> activeConnections;

		private Dictionary<Vector3, Connection> potentialConnections;

		private Dictionary<Vector3, Connection> falsePotentialConnections;

		public GameMap Map => map;

		public virtual BoundsMap<Tile> BoundsMap => Map.BoundsMap;

		public int Count => doorways.Count;

		public virtual bool IsReadOnly => false;

		public virtual byte DoorPosPrecision => 3;

		public virtual float DoorPrecision => 1f / (float)(1 << (int)DoorPosPrecision);

		protected virtual float clearancePrecision => 1f;

		protected virtual float maxClearance => clearancePrecision * 256f;

		public IReadOnlyCollection<Doorway> Leaves => leaves.Values;

		public IReadOnlyCollection<Connection> ActiveConnections => activeConnections;

		public IReadOnlyCollection<Connection> PotentialConnections => potentialConnections.Values;

		public IReadOnlyCollection<Connection> FalsePotentialConnections => falsePotentialConnections.Values;

		public DoorwayManager(GameMap map)
		{
			this.map = map;
			doorways = new Dictionary<Doorway, DoorType>();
			leaves = new Dictionary<Vector3, Doorway>();
			activeConnections = new HashSet<Connection>();
			potentialConnections = new Dictionary<Vector3, Connection>();
			falsePotentialConnections = new Dictionary<Vector3, Connection>();
		}

		public bool Validate()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<Doorway, DoorType> doorway in doorways)
			{
				Doorway key = doorway.Key;
				if ((Object)(object)key == (Object)null)
				{
					return false;
				}
				DoorType value = doorway.Value;
				Vector3 key2 = ApproxPosition(key);
				Connection value2;
				switch (value)
				{
				case DoorType.LEAF:
				{
					if (!leaves.TryGetValue(key2, out var value3) || (Object)(object)key != (Object)(object)value3)
					{
						return false;
					}
					break;
				}
				case DoorType.ACTIVE_CONNECTOR:
					if (!activeConnections.Contains(new Connection(key, key.Connection)))
					{
						return false;
					}
					break;
				case DoorType.POTENTIAL_CONNECTOR:
					if (!potentialConnections.TryGetValue(key2, out value2) || ((Object)(object)value2.d1 != (Object)(object)key && (Object)(object)value2.d2 != (Object)(object)key))
					{
						return false;
					}
					break;
				case DoorType.FALSE_POTENTIAL_CONNECTOR:
					if (!falsePotentialConnections.TryGetValue(key2, out value2) || ((Object)(object)value2.d1 != (Object)(object)key && (Object)(object)value2.d2 != (Object)(object)key))
					{
						return false;
					}
					break;
				default:
					return false;
				}
			}
			return true;
		}

		protected virtual void UnsetDoorway(Doorway d, Vector3 approxPos = default(Vector3))
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			if (!doorways.TryGetValue(d, out var value))
			{
				return;
			}
			if (approxPos == default(Vector3))
			{
				approxPos = ApproxPosition(d);
			}
			Connection value2;
			switch (value)
			{
			case DoorType.LEAF:
			{
				if (!leaves.Remove(approxPos, out var value3) || (Object)(object)value3 != (Object)(object)d)
				{
					throw new InvalidOperationException("Desync between leaves and doorways");
				}
				break;
			}
			case DoorType.ACTIVE_CONNECTOR:
				activeConnections.Remove(new Connection(d, d.Connection));
				break;
			case DoorType.POTENTIAL_CONNECTOR:
				if (potentialConnections.Remove(approxPos, out value2) && (Object)(object)value2.d1 != (Object)(object)d && (Object)(object)value2.d2 != (Object)(object)d)
				{
					throw new InvalidOperationException("Desync between potentialConnections and doorways");
				}
				break;
			case DoorType.FALSE_POTENTIAL_CONNECTOR:
				if (falsePotentialConnections.Remove(approxPos, out value2) && (Object)(object)value2.d1 != (Object)(object)d && (Object)(object)value2.d2 != (Object)(object)d)
				{
					throw new InvalidOperationException("Desync between falsePotentialConnections and doorways");
				}
				break;
			}
		}

		protected virtual void SetLeaf(Doorway d, Vector3 approxPos = default(Vector3))
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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)
			if (approxPos == default(Vector3))
			{
				approxPos = ApproxPosition(d);
			}
			if (leaves.ContainsKey(approxPos))
			{
				throw new InvalidOperationException($"How do we have two leaves at {approxPos}? ({d} & leaves[approxPos])");
			}
			UnsetDoorway(d);
			doorways[d] = DoorType.LEAF;
			leaves.Add(approxPos, d);
		}

		protected virtual void SetActiveConnector(Doorway d)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			UnsetDoorway(d);
			UnsetDoorway(d.Connection);
			doorways[d] = DoorType.ACTIVE_CONNECTOR;
			if (doorways.ContainsKey(d.Connection))
			{
				doorways[d.Connection] = DoorType.ACTIVE_CONNECTOR;
			}
			activeConnections.Add(new Connection(d, d.Connection));
		}

		protected virtual void SetPotentialConnection(Connection c, Vector3 approxPos = default(Vector3))
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_00e5: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: 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)
			if (approxPos == default(Vector3))
			{
				approxPos = ApproxPosition(c.d1);
			}
			UnsetDoorway(c.d1);
			UnsetDoorway(c.d2);
			if (c.d1.Fits(c.d2))
			{
				if (potentialConnections.ContainsKey(approxPos))
				{
					Plugin.LogError($"Two potential connections at the same position? ({approxPos})");
					return;
				}
				doorways[c.d1] = DoorType.POTENTIAL_CONNECTOR;
				if (doorways.ContainsKey(c.d2))
				{
					doorways[c.d2] = DoorType.POTENTIAL_CONNECTOR;
				}
				potentialConnections.Add(approxPos, c);
			}
			else if (falsePotentialConnections.ContainsKey(approxPos))
			{
				Plugin.LogError($"Two false potential connections at the same position? ({approxPos})");
			}
			else
			{
				doorways[c.d1] = DoorType.FALSE_POTENTIAL_CONNECTOR;
				if (doorways.ContainsKey(c.d2))
				{
					doorways[c.d2] = DoorType.FALSE_POTENTIAL_CONNECTOR;
				}
				falsePotentialConnections.Add(approxPos, c);
			}
		}

		public void Add(Doorway d)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)d == (Object)null)
			{
				Debug.LogException((Exception)new ArgumentNullException("Doorway d"));
			}
			else
			{
				if (Contains(d))
				{
					return;
				}
				Subscribe(d);
				if (d.IsVacant)
				{
					Vector3 val = ApproxPosition(d);
					if (leaves.TryGetValue(val, out var value))
					{
						SetPotentialConnection(new Connection(d, value), val);
					}
					else
					{
						SetLeaf(d, val);
					}
				}
				else
				{
					SetActiveConnector(d);
				}
			}
		}

		private void RemoveAction(Doorway d)
		{
			if (!Remove(d))
			{
				Debug.LogError((object)$"Failed to remove doorway {(((Object)(object)d == (Object)null) ? ((object?)d) : ((object?)((Object)d).name))} from DoorwayManager");
			}
		}

		public bool Remove(Doorway d)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_013a: Unknown result type (might be due to invalid IL or missing references)
			if (!doorways.ContainsKey(d))
			{
				return false;
			}
			Unsubscribe(d);
			Connection value;
			switch (doorways[d])
			{
			case DoorType.LEAF:
			{
				if (!leaves.Remove(ApproxPosition(d), out var value2) || (Object)(object)d != (Object)(object)value2)
				{
					Debug.LogWarning((object)"DoorwayManager: Desync between doorways and leaves, this *will* become a problem");
				}
				break;
			}
			case DoorType.ACTIVE_CONNECTOR:
				if (!Contains(d.Connection))
				{
					activeConnections.Remove(new Connection(d, d.Connection));
				}
				break;
			case DoorType.POTENTIAL_CONNECTOR:
			{
				potentialConnections.Remove(ApproxPosition(d), out value);
				Doorway other = value.GetOther(d);
				if (Contains(other))
				{
					SetLeaf(other);
				}
				break;
			}
			case DoorType.FALSE_POTENTIAL_CONNECTOR:
			{
				falsePotentialConnections.Remove(ApproxPosition(d), out value);
				Doorway other = value.GetOther(d);
				if (Contains(other))
				{
					SetLeaf(other);
				}
				break;
			}
			}
			doorways.Remove(d);
			return true;
		}

		public bool Contains(Doorway d)
		{
			return doorways.ContainsKey(d);
		}

		public virtual void Clear()
		{
			doorways.Clear();
			leaves.Clear();
			activeConnections.Clear();
			potentialConnections.Clear();
			falsePotentialConnections.Clear();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		public IEnumerator<Doorway> GetEnumerator()
		{
			return doorways.Keys.GetEnumerator();
		}

		public void CopyTo(Doorway[] arr, int startIdx)
		{
			throw new NotImplementedException();
		}

		protected virtual void Subscribe(Doorway d)
		{
			d.OnDestroyEvent += RemoveAction;
			d.OnDisconnectEvent += DisconnectDoor;
			d.OnConnectEvent += ConnectDoor;
		}

		protected virtual void Unsubscribe(Doorway d)
		{
			d.OnDestroyEvent -= RemoveAction;
			d.OnDisconnectEvent -= DisconnectDoor;
			d.OnConnectEvent -= ConnectDoor;
		}

		public virtual Vector3 ApproxPosition(Doorway door)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0062: 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_007d: 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)
			if ((Object)(object)door == (Object)null)
			{
				throw new NullReferenceException("Cannot get the position of a destroyed doorway. ");
			}
			Vector3 position = ((Component)door).transform.position;
			return new Vector3(DoorPrecision * (float)(int)(position.x / DoorPrecision + 0.5f), DoorPrecision * (float)(int)(position.y / DoorPrecision + 0.5f), DoorPrecision * (float)(int)(position.z / DoorPrecision + 0.5f));
		}

		public virtual float ClearanceRadius(Doorway d)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			float num = clearancePrecision;
			Bounds bounds = default(Bounds);
			do
			{
				((Bounds)(ref bounds))..ctor(((Component)d).transform.position + num * ((Component)d).transform.forward, 2f * num * Vector3.one);
				if (BoundsMap.Intersects(bounds))
				{
					break;
				}
				num *= 2f;
			}
			while (!(num >= maxClearance));
			return num;
		}

		public IChoice<Doorway, float> GetLeaves(Func<Doorway, float> weightFunc)
		{
			WeightedChoiceList<Doorway> weightedChoiceList = new WeightedChoiceList<Doorway>();
			foreach (Doorway value in leaves.Values)
			{
				weightedChoiceList.Add(value, weightFunc(value));
			}
			return weightedChoiceList;
		}

		public IChoice<Connection, float> GetActiveConnections(Func<Connection, float> weightFunc)
		{
			WeightedChoiceList<Connection> weightedChoiceList = new WeightedChoiceList<Connection>();
			foreach (Connection activeConnection in activeConnections)
			{
				weightedChoiceList.Add(activeConnection, weightFunc(activeConnection));
			}
			return weightedChoiceList;
		}

		public IChoice<Connection, float> GetPotentialConnections(Func<Connection, float> weightFunc)
		{
			WeightedChoiceList<Connection> weightedChoiceList = new WeightedChoiceList<Connection>();
			foreach (Connection value in potentialConnections.Values)
			{
				weightedChoiceList.Add(value, weightFunc(value));
			}
			return weightedChoiceList;
		}

		public void DisconnectDoor(Doorway d)
		{
			//IL_0009: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (leaves.TryGetValue(ApproxPosition(d), out var value))
			{
				SetPotentialConnection(new Connection(d, value));
			}
			else
			{
				SetLeaf(d);
			}
		}

		public void ConnectDoor(Doorway d1, Doorway d2)
		{
			SetActiveConnector(d1);
		}
	}
	public struct Connection : IEquatable<Connection>, IEquatable<ITuple>
	{
		public Doorway d1;

		public Doorway d2;

		public Connection(Doorway d1, Doorway d2)
		{
			this.d1 = d1;
			this.d2 = d2;
		}

		public Doorway GetOther(Doorway d)
		{
			if ((Object)(object)d != (Object)(object)d1 && (Object)(object)d != (Object)(object)d2)
			{
				throw new ArgumentException("Doorway expected to be one of the doorways in the connection");
			}
			return ((Object)(object)d == (Object)(object)d1) ? d2 : d1;
		}

		public void Deconstruct(out Doorway d1, out Doorway d2)
		{
			d1 = this.d1;
			d2 = this.d2;
		}

		public override bool Equals(object other)
		{
			if (other is ITuple tup)
			{
				return Equals(tup);
			}
			if (other is Connection con)
			{
				return Equals(con);
			}
			return false;
		}

		public bool Equals(Connection con)
		{
			Connection connection = con;
			var (doorway3, doorway4) = (Connection)(ref connection);
			return ((Object)(object)d1 == (Object)(object)doorway3 && (Object)(object)d2 == (Object)(object)doorway4) || ((Object)(object)d1 == (Object)(object)doorway4 && (Object)(object)d2 == (Object)(object)doorway3);
		}

		public bool Equals(ITuple tup)
		{
			if (tup.Length != 2)
			{
				return false;
			}
			Doorway doorway;
			Doorway doorway2;
			try
			{
				doorway = (Doorway)tup[0];
				doorway2 = (Doorway)tup[1];
			}
			catch (InvalidCastException)
			{
				return false;
			}
			return ((Object)(object)d1 == (Object)(object)doorway && (Object)(object)d2 == (Object)(object)doorway2) || ((Object)(object)d1 == (Object)(object)doorway2 && (Object)(object)d2 == (Object)(object)doorway);
		}

		public override int GetHashCode()
		{
			return ((object)d1).GetHashCode() ^ ((object)d2).GetHashCode();
		}
	}
	public class Doorway : MonoBehaviour
	{
		protected bool initialized;

		protected Tile tile;

		protected Vector2 size;

		protected Doorway connection;

		public Tile Tile
		{
			get
			{
				if ((Object)(object)this.tile == (Object)null)
				{
					this.tile = null;
					Tile[] componentsInParent = ((Component)this).GetComponentsInParent<Tile>(((Component)this).gameObject.activeInHierarchy);
					foreach (Tile tile in componentsInParent)
					{
						if (tile.Initialized)
						{
							this.tile = tile;
							break;
						}
					}
				}
				return this.tile;
			}
		}

		public Vector2 Size
		{
			get
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				return size;
			}
			protected set
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				size = value;
			}
		}

		public bool IsVacant => (Object)(object)connection == (Object)null;

		public bool Initialized
		{
			get
			{
				return initialized;
			}
			protected set
			{
				initialized = value;
			}
		}

		public Doorway Connection => connection;

		public event Action<Doorway> OnDisconnectEvent;

		public event Action<Doorway> OnDestroyEvent;

		public event Action<Doorway, Doorway> OnConnectEvent;

		private void OnDestroy()
		{
			Disconnect();
			this.OnDestroyEvent?.Invoke(this);
		}

		public virtual void Initialize()
		{
			if (!Initialized)
			{
				Initialized = true;
				connection = null;
			}
		}

		public virtual bool Fits(Doorway other)
		{
			//IL_0002: 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)
			return size == other.size;
		}

		public void Connect(Doorway other)
		{
			if (!Fits(other))
			{
				string message = "Cannot connect doors that do not fit together\n" + $"\t(Tiles {Tile} & {other.Tile})";
				throw new ArgumentException(message);
			}
			connection = other;
			other.connection = this;
			this.OnConnectEvent?.Invoke(this, other);
			other.OnConnectEvent?.Invoke(other, this);
		}

		public void Disconnect()
		{
			if (!((Object)(object)connection == (Object)null))
			{
				this.OnDisconnectEvent?.Invoke(this);
				Doorway doorway = connection;
				connection = null;
				doorway.Disconnect();
			}
		}
	}
	public class Tile : MonoBehaviour
	{
		protected Doorway[] doorways = null;

		protected Bounds bounding_box = new Bounds(Vector3.zero, Vector3.zero);

		protected bool initialized = false;

		public bool Initialized
		{
			get
			{
				return initialized;
			}
			protected set
			{
				initialized = value;
			}
		}

		public bool HasLeafDoorway
		{
			get
			{
				Doorway[] array = Doorways;
				foreach (Doorway doorway in array)
				{
					if (doorway.IsVacant)
					{
						return true;
					}
				}
				return false;
			}
		}

		public bool IsPrefab
		{
			get
			{
				//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)
				Scene scene = ((Component)this).gameObject.scene;
				return !((Scene)(ref scene)).IsValid();
			}
		}

		public Doorway[] Doorways => doorways ?? (doorways = ((Component)this).GetComponentsInChildren<Doorway>());

		public virtual float IntersectionTolerance => 0.625f;

		public Bounds LooseBoundingBox
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				Bounds boundingBox = BoundingBox;
				Vector3 center = ((Bounds)(ref boundingBox)).center;
				boundingBox = BoundingBox;
				return new Bounds(center, ((Bounds)(ref boundingBox)).size - 2f * IntersectionTolerance * Vector3.one);
			}
		}

		public Bounds BoundingBox => bounding_box;

		public GameMap Map => ((Component)this).GetComponentInParent<GameMap>(true);

		public Tile Instantiate(Transform parent = null)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//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)
			Tile component = Object.Instantiate<GameObject>(((Component)this).gameObject).GetComponent<Tile>();
			component.bounding_box = new Bounds(Vector3.zero, Vector3.zero);
			((Component)component).transform.parent = parent;
			component.Initialize(this);
			return component;
		}

		public virtual void Initialize(Tile prefab)
		{
			if (!initialized)
			{
				initialized = true;
			}
		}

		public void RotateBy(Quaternion quat)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Bounds)(ref bounding_box)).center - ((Component)this).transform.position;
			((Bounds)(ref bounding_box)).center = ((Component)this).transform.position + quat * val;
			((Bounds)(ref bounding_box)).extents = quat * ((Bounds)(ref bounding_box)).extents;
			bounding_box.FixExtents();
			((Component)this).transform.Rotate(((Quaternion)(ref quat)).eulerAngles, (Space)0);
		}

		public void MoveTo(Vector3 pos)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_0031: 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)
			Vector3 val = ((Component)this).transform.position - ((Bounds)(ref bounding_box)).center;
			((Bounds)(ref bounding_box)).center = pos;
			((Component)this).transform.position = pos + val;
		}

		public bool PlaceAsRoot(Transform parent)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.parent = parent;
			MoveTo(parent.position);
			return true;
		}

		public bool Place(int thisDoorwayIdx, Doorway other)
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: 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_0111: 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_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: 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_0136: Unknown result type (might be due to invalid IL or missing references)
			if (thisDoorwayIdx >= Doorways.Length)
			{
				throw new IndexOutOfRangeException($"Door index of new tile out of range. Tried to select idx {thisDoorwayIdx} with only {Doorways.Length} doors. ");
			}
			if ((Object)(object)this == (Object)null)
			{
				throw new ArgumentNullException("Cannot place a tile that is being destroyed");
			}
			if ((Object)(object)other == (Object)null)
			{
				throw new ArgumentNullException("No doorway provided to connect to");
			}
			if ((Object)(object)other.Tile.Map == (Object)null)
			{
				throw new ArgumentException("Tile must connect to a doorway that is placed within a map");
			}
			Transform parent = ((Component)this).transform.parent;
			((Component)this).transform.parent = ((Component)other).transform;
			Doorway doorway = Doorways[thisDoorwayIdx];
			Vector3 up = ((Component)doorway).transform.up;
			Quaternion quat = Quaternion.Inverse(((Component)doorway).transform.rotation) * ((Component)other).transform.rotation * new Quaternion(up.x, up.y, up.z, 0f);
			RotateBy(quat);
			Vector3 val = ((Component)doorway).transform.position - ((Bounds)(ref bounding_box)).center;
			MoveTo(((Component)other).transform.position - val);
			if (!Map.VerifyTilePlacement(new PlacementInfo(this, thisDoorwayIdx, other)))
			{
				((Component)this).transform.SetParent(parent);
				return false;
			}
			doorway.Connect(other);
			return true;
		}

		public virtual byte[] GetSerializationId()
		{
			return (((Object)this).name.Substring(0, ((Object)this).name.Length - "(Clone)".Length) + "\0").GetBytes();
		}

		public virtual Tile GetPrefab(object ident)
		{
			return GetPrefab((string)ident);
		}

		public static Tile GetPrefab(string id)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			Object[] array = Resources.FindObjectsOfTypeAll(typeof(Tile));
			for (int i = 0; i < array.Length; i++)
			{
				Tile tile = (Tile)(object)array[i];
				if (((Object)tile).name == id)
				{
					Scene scene = ((Component)tile).gameObject.scene;
					if (!((Scene)(ref scene)).IsValid())
					{
						return tile;
					}
				}
			}
			return null;
		}
	}
	public abstract class GenerationAction
	{
	}
	public class YieldFrame : GenerationAction
	{
	}
	public class PlacementInfo : GenerationAction
	{
		private Tile newtile;

		private int newDoorwayIdx;

		private Doorway attachmentPoint;

		public Tile NewTile
		{
			get
			{
				return newtile;
			}
			set
			{
				newtile = value;
			}
		}

		public int NewDoorwayIdx
		{
			get
			{
				return newDoorwayIdx;
			}
			set
			{
				newDoorwayIdx = value;
			}
		}

		public Doorway AttachmentPoint
		{
			get
			{
				return attachmentPoint;
			}
			set
			{
				attachmentPoint = value;
			}
		}

		public PlacementInfo(Tile newTile, int newDoorwayIdx = 0, Doorway attachmentPoint = null)
		{
			newtile = newTile;
			this.newDoorwayIdx = newDoorwayIdx;
			this.attachmentPoint = attachmentPoint;
		}

		public override string ToString()
		{
			return "PlacementInfo: " + ((Object)newtile).name + ":" + ((Object)newtile.Doorways[newDoorwayIdx]).name + " onto " + ((Object)attachmentPoint.Tile).name + ":" + ((Object)attachmentPoint).name;
		}
	}
	public class RemovalInfo : GenerationAction
	{
		private Tile target;

		public Tile Target => target;

		public RemovalInfo(Tile target)
		{
			this.target = target;
		}
	}
	public abstract class ConnectionAction : GenerationAction
	{
		public Doorway d1 { get; private set; }

		public Doorway d2 { get; private set; }

		public (Doorway d1, Doorway d2) Doorways => (d1, d2);

		public ConnectionAction(Doorway d1, Doorway d2)
		{
			this.d1 = d1;
			this.d2 = d2;
			if (!d1.Fits(d2))
			{
				throw new ArgumentException($"Doors {d1} and {d2} do not fit together");
			}
		}
	}
	public class ConnectAction : ConnectionAction
	{
		public ConnectAction(Doorway d1, Doorway d2)
			: base(d1, d2)
		{
		}
	}
	public class DisconnectAction : ConnectionAction
	{
		public DisconnectAction(Doorway d1, Doorway d2)
			: base(d1, d2)
		{
		}
	}
	public interface ITileGenerator
	{
		IEnumerable<GenerationAction> Generator(GameMap map);
	}
	public class GameMap : MonoBehaviour
	{
		protected Tile rootTile;

		private BoundsMap<Tile> boundsMap;

		protected NavMeshSurface navSurface;

		public Tile RootTile
		{
			get
			{
				return rootTile;
			}
			protected set
			{
				rootTile = value;
			}
		}

		public int TileCount => ((Component)this).GetComponentsInChildren<Tile>().Length;

		public BoundsMap<Tile> BoundsMap
		{
			get
			{
				return boundsMap;
			}
			private set
			{
				boundsMap = value;
			}
		}

		public virtual IDoorwayManager DoorwayManager { get; protected set; } = null;


		public event Action<Tile> TileInsertionEvent;

		public event Action<Tile> TileRemovalEvent;

		public event Action<GameMap> GenerationCompleteEvent;

		protected virtual void Awake()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			rootTile = null;
			if (DoorwayManager == null)
			{
				DoorwayManager = new DoorwayManager(this);
			}
			boundsMap = new BoundsMap<Tile>(Vector3.zero, 1024f, (Tile t) => t.LooseBoundingBox);
			navSurface = ((Component)this).gameObject.AddComponent<NavMeshSurface>();
			navSurface.collectObjects = (CollectObjects)2;
			navSurface.useGeometry = (NavMeshCollectGeometry)1;
			TileRemovalEvent += RemoveTileAction;
		}

		protected virtual void OnDestroy()
		{
			navSurface.RemoveData();
		}

		public virtual bool PerformAction(GenerationAction action)
		{
			if (action is PlacementInfo placement)
			{
				this.TileInsertionEvent?.Invoke(AddTile(placement));
			}
			else if (action is RemovalInfo removal)
			{
				RemoveTile(removal);
			}
			else if (action is ConnectAction connectAction)
			{
				var (doorway, other) = connectAction.Doorways;
				doorway.Connect(other);
			}
			else if (action is DisconnectAction disconnectAction)
			{
				disconnectAction.d1.Disconnect();
			}
			else if (!(action is YieldFrame))
			{
				return false;
			}
			return true;
		}

		public virtual IEnumerator GenerateCoroutine(ITileGenerator tileGen)
		{
			foreach (GenerationAction action in tileGen.Generator(this))
			{
				if (!PerformAction(action))
				{
					throw new InvalidOperationException($"Unknown GenerationAction: {action}");
				}
				if (action is YieldFrame)
				{
					yield return null;
				}
			}
			this.GenerationCompleteEvent?.Invoke(this);
		}

		protected void AddDoorway(Doorway d)
		{
			if ((Object)(object)d == (Object)null)
			{
				Debug.LogError((object)("Cannot add null doorway to " + ((object)this).GetType().Name + ". Is it destroyed?"), (Object)(object)this);
			}
			else
			{
				DoorwayManager.Add(d);
			}
		}

		protected void RemoveDoorway(Doorway d)
		{
			if ((Object)(object)d == (Object)null)
			{
				throw new NullReferenceException("Cannot remove a leaf that has already been destroyed");
			}
			if (!DoorwayManager.Remove(d))
			{
				Debug.LogError((object)("Doorway " + ((Object)d.Tile).name + ":" + ((Object)d).name + " not found/removed"), (Object)(object)this);
			}
		}

		public virtual bool VerifyTilePlacement(PlacementInfo placement)
		{
			Tile newTile = placement.NewTile;
			if ((Object)(object)newTile == (Object)null)
			{
				Debug.LogException((Exception)new ArgumentNullException("Tile tile"), (Object)(object)this);
				return false;
			}
			return !boundsMap.Intersects(newTile);
		}

		public virtual Tile AddTile(PlacementInfo placement)
		{
			Tile tile = placement.NewTile;
			if (tile.IsPrefab)
			{
				tile = tile.Instantiate(((Component)this).transform);
			}
			if ((Object)(object)RootTile == (Object)null)
			{
				RootTile = tile;
				RootTile.PlaceAsRoot(((Component)this).transform);
			}
			else
			{
				Doorway attachmentPoint = placement.AttachmentPoint;
				int newDoorwayIdx = placement.NewDoorwayIdx;
				if (!attachmentPoint.Fits(tile.Doorways[newDoorwayIdx]) || !tile.Place(newDoorwayIdx, attachmentPoint))
				{
					Object.Destroy((Object)(object)((Component)tile).gameObject);
					return null;
				}
			}
			Doorway[] doorways = tile.Doorways;
			foreach (Doorway d in doorways)
			{
				AddDoorway(d);
			}
			try
			{
				boundsMap.Add(tile);
			}
			catch (ArgumentException)
			{
				RemoveTile(new RemovalInfo(tile));
				if ((Object)(object)tile != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)tile).gameObject);
				}
				tile = null;
			}
			return tile;
		}

		private void RemoveTileAction(Tile t)
		{
			if (!boundsMap.Remove(t))
			{
				Debug.LogError((object)("Tile " + ((Object)t).name + " was not in boundsMap?"));
			}
		}

		public void RemoveTile(RemovalInfo removal)
		{
			if ((Object)(object)removal.Target == (Object)null)
			{
				Debug.LogError((object)"Cannot remove tile that has already been destroyed");
				return;
			}
			Tile[] componentsInChildren = ((Component)removal.Target).GetComponentsInChildren<Tile>(((Component)this).gameObject.activeInHierarchy);
			foreach (Tile obj in componentsInChildren)
			{
				this.TileRemovalEvent?.Invoke(obj);
			}
			Object.Destroy((Object)(object)((Component)removal.Target).gameObject);
		}

		public void GenerateNavMesh(int agentId)
		{
			navSurface.RemoveData();
			navSurface.agentTypeID = agentId;
			navSurface.BuildNavMesh();
			navSurface.AddData();
		}
	}
	public class GameMapSerializer<T, TTile> : Serializer<T> where T : GameMap where TTile : Tile
	{
		protected ISerializer<TTile> TileSer;

		public GameMapSerializer(ISerializer<TTile> tileSerializer)
		{
			TileSer = tileSerializer;
		}

		public override void Serialize(SerializationContext sc, T map)
		{
			sc.Add(((Object)map).name.GetBytes());
			sc.Add(new byte[1]);
			sc.AddInline(map.RootTile, TileSer);
		}

		protected override T Deserialize(T map, DeserializationContext dc)
		{
			map.AddTile(new PlacementInfo((TTile)dc.ConsumeInline(TileSer)));
			return map;
		}

		public override T Deserialize(DeserializationContext dc)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			dc.ConsumeUntil((byte b) => b == 0).CastInto(out string str);
			dc.Consume(1);
			T baseObject = new GameObject(str).AddComponent<T>();
			return Deserialize(baseObject, dc);
		}
	}
	public class TileSerializer<T> : Serializer<T> where T : Tile
	{
		protected GameMap ParentMap;

		public TileSerializer(GameMap map)
		{
			ParentMap = map;
		}

		public override void Serialize(SerializationContext sc, T tgt)
		{
			sc.Add(tgt.GetSerializationId());
			sc.Add(((ushort)tgt.Doorways.Length).GetBytes());
			Doorway[] doorways = tgt.Doorways;
			foreach (Doorway doorway in doorways)
			{
				sc.AddReference(doorway.Connection?.Tile, this);
				if ((Object)(object)doorway.Connection == (Object)null)
				{
					sc.Add(((ushort)0).GetBytes());
				}
				else
				{
					sc.Add(((ushort)Array.IndexOf(doorway.Connection.Tile.Doorways, doorway.Connection)).GetBytes());
				}
			}
		}

		protected override T Deserialize(T tile, DeserializationContext dc)
		{
			int address = dc.Address;
			bool flag = false;
			dc.Consume(2).CastInto(out ushort o);
			for (int i = 0; i < o; i++)
			{
				int num = i;
				int num2 = dc.ConsumeReference(this);
				dc.Consume(2).CastInto(out ushort o2);
				if (num2 == 0)
				{
					continue;
				}
				if (num2 < address)
				{
					T val = (T)dc.GetReference(num2);
					if (DeserializationContext.Verbose)
					{
						Plugin.LogDebug($"Attaching {((Object)tile).name}:{num} to {((Object)val).name}:{o2}");
					}
					if (!flag)
					{
						flag = true;
						ParentMap.AddTile(new PlacementInfo(tile, num, val.Doorways[o2]));
					}
					else
					{
						ParentMap.PerformAction(new ConnectAction(tile.Doorways[num], val.Doorways[o2]));
					}
				}
				else if (num2 == address)
				{
					throw new Exception("Tile connects to itself??");
				}
			}
			return tile;
		}

		public override T Deserialize(DeserializationContext dc)
		{
			int address = dc.Address;
			dc.ConsumeUntil((byte b) => b == 0).CastInto(out string str);
			dc.Consume(1);
			T val = (T)(Tile.GetPrefab(str)?.Instantiate(((Component)ParentMap).transform));
			if ((Object)(object)val == (Object)null)
			{
				throw new NullReferenceException("Could not find a prefab with id '" + str + "'");
			}
			return Deserialize(val, dc);
		}
	}
	public class PropAction : GenerationAction
	{
		protected Prop target;

		protected bool enable;

		public Prop Prop => target;

		public bool Enable => enable;

		public PropAction(Prop t, bool e)
		{
			target = t;
			enable = e;
		}
	}
	internal sealed class ArchetypeRegionPlacer : IDisposable
	{
		private GameMap map;

		private Doorway root;

		private Archetype archetype;

		private HashSet<DTile> tilesPlaced;

		private DoorwayManager doorwayManager;

		private WeightedChoiceList<DTile> possibleTiles;

		private Tile tile;

		private ChoiceList<Doorway> possibleDoorways;

		private Doorway doorway;

		private IChoice<Doorway, float> possibleLeaves;

		private Doorway leaf;

		public DungeonFlowConverter parent { get; private set; }

		public int iterationsSinceLastSuccess { get; private set; }

		private int NumLeaves => doorwayManager.Leaves.Count;

		public Random Rng => parent.Rng;

		public bool Exhausted => ((Object)(object)tile == (Object)null && possibleTiles.OpenCount == 0) || NumLeaves == 0;

		public ArchetypeRegionPlacer(DungeonFlowConverter parent, GameMap map, Doorway root, Archetype archetype, HashSet<DTile> tilesPlaced)
		{
			if (parent == null)
			{
				throw new ArgumentNullException("parent");
			}
			if ((Object)(object)map == (Object)null)
			{
				throw new ArgumentNullException("map");
			}
			if ((Object)(object)root == (Object)null)
			{
				throw new ArgumentNullException("root");
			}
			if (archetype == null)
			{
				throw new ArgumentNullException("archetype");
			}
			if (tilesPlaced == null)
			{
				throw new ArgumentNullException("tilesPlaced");
			}
			this.parent = parent;
			this.map = map;
			this.root = root;
			this.archetype = archetype;
			this.tilesPlaced = tilesPlaced;
			doorwayManager = new DoorwayManager(map);
			AddDoorway(root);
			possibleDoorways = null;
			possibleLeaves = null;
			iterationsSinceLastSuccess = 0;
			possibleTiles = new WeightedChoiceList<DTile>(archetype.Tiles);
			tile = null;
			doorway = (leaf = null);
			map.TileInsertionEvent += Handler;
		}

		~ArchetypeRegionPlacer()
		{
			Dispose(isDisposing: false);
		}

		public void Dispose()
		{
			Dispose(isDisposing: true);
			GC.SuppressFinalize(this);
		}

		private void Dispose(bool isDisposing)
		{
			if (isDisposing)
			{
				map.TileInsertionEvent -= Handler;
			}
		}

		public PlacementInfo YieldAttempt()
		{
			do
			{
				GetNewLeaf();
			}
			while ((Object)(object)leaf == (Object)null && !Exhausted);
			if (Exhausted)
			{
				return null;
			}
			if ((Object)(object)leaf == (Object)null)
			{
				throw new Exception("null leaf with no exhaustion?");
			}
			PlacementInfo placementInfo = new PlacementInfo(tile, Array.IndexOf(tile.Doorways, doorway), leaf);
			if (Config.Singleton.EnableVerboseGeneration)
			{
				Plugin.LogDebug($"Trying {placementInfo}");
			}
			return placementInfo;
		}

		private void Handler(Tile t)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			if ((Object)(object)t != (Object)null)
			{
				Doorway[] doorways = t.Doorways;
				foreach (Doorway doorway in doorways)
				{
					AddDoorway(doorway);
				}
				if ((int)((Component)tile).GetComponent<Tile>().RepeatMode == 2)
				{
					tilesPlaced.Add((DTile)tile);
				}
				tile = null;
				this.doorway = (leaf = null);
				possibleTiles.Reset();
				iterationsSinceLastSuccess = 0;
			}
			else
			{
				if (Config.Singleton.EnableVerboseGeneration)
				{
					Plugin.LogDebug("Placement Failed");
				}
				iterationsSinceLastSuccess++;
			}
		}

		private void GetNewLeaf()
		{
			if ((Object)(object)doorway == (Object)null || possibleLeaves.OpenCount == 0)
			{
				GetNewDoorway();
				if ((Object)(object)doorway == (Object)null || possibleLeaves.OpenCount == 0)
				{
					leaf = null;
					return;
				}
			}
			leaf = possibleLeaves.Yield((float)((double)possibleLeaves.OpenWidth * Rng.NextDouble()));
		}

		private void GetNewDoorway()
		{
			if ((Object)(object)tile == (Object)null || possibleDoorways.OpenCount == 0)
			{
				do
				{
					GetNewTile();
				}
				while (tilesPlaced.Contains((DTile)tile) && !Exhausted);
				if ((Object)(object)tile == (Object)null)
				{
					doorway = null;
					return;
				}
			}
			doorway = possibleDoorways.Yield(Rng.Next(possibleDoorways.OpenCount));
			possibleLeaves = doorwayManager.GetLeaves((Doorway d) => (d.Size == doorway.Size) ? doorwayManager.ClearanceRadius(d) : 0f);
		}

		private void GetNewTile()
		{
			if (possibleTiles.OpenCount == 0)
			{
				tile = null;
				return;
			}
			tile = possibleTiles.Yield((float)((double)possibleTiles.OpenWidth * Rng.NextDouble()));
			possibleDoorways = new ChoiceList<Doorway>(tile.Doorways);
		}

		private void AddDoorway(Doorway leaf)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (archetype.GetDoorwayCountBySize(leaf.Size) != 0)
			{
				doorwayManager.Add(leaf);
				possibleLeaves = null;
			}
		}
	}
	public class Archetype
	{
		public WeightedList<DTile> Tiles;

		public Dictionary<Vector2, int> DoorwayCountBySize;

		public float Length;

		public Archetype(float length)
		{
			Tiles = new WeightedList<DTile>();
			DoorwayCountBySize = new Dictionary<Vector2, int>();
			Length = length;
		}

		public void AddTile(DTile tile, float weight)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			Tiles.Add(tile, weight);
			Doorway[] doorways = tile.Doorways;
			foreach (Doorway doorway in doorways)
			{
				try
				{
					DoorwayCountBySize[doorway.Size]++;
				}
				catch (KeyNotFoundException)
				{
					DoorwayCountBySize.Add(doorway.Size, 1);
				}
			}
		}

		public int GetDoorwayCountBySize(Vector2 size)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			if (!DoorwayCountBySize.TryGetValue(size, out var value))
			{
				return 0;
			}
			return value;
		}
	}
	public class DungeonFlowConverter : ITileGenerator
	{
		protected DungeonFlow flow;

		protected DTile StartRoom;

		protected List<List<Archetype>> archetypes;

		protected HashSet<DTile> tilesPlaced;

		private const int MAX_ATTEMPTS = 10;

		private int iterationsSinceLastSuccess = 0;

		private int seed;

		private Random rng;

		public int TileCountLowerBound { get; protected set; }

		public int TileCountUpperBound { get; protected set; }

		public int TileCountAverage => (TileCountLowerBound + TileCountUpperBound) / 2;

		public int PlacementLowerBound => (int)(Config.Singleton.LowerIterationMultiplier * (float)TileCountLowerBound);

		public int PlacementUpperBound => (int)(Config.Singleton.UpperIterationMultiplier * (float)TileCountLowerBound);

		public int Seed
		{
			get
			{
				return seed;
			}
			set
			{
				rng = new Random(value);
				seed = value;
			}
		}

		public Random Rng => rng;

		public DungeonFlow Flow => flow;

		public float DoorwayConnectionChance => flow.DoorwayConnectionChance / 2f;

		public float DoorwayDisconnectChance => flow.DoorwayConnectionChance / 2f;

		public DungeonFlowConverter(DungeonFlow flow, int seed)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Invalid comparison between Unknown and I4
			Seed = seed;
			tilesPlaced = new HashSet<DTile>();
			this.flow = flow;
			GraphNode node = null;
			foreach (GraphNode node2 in flow.Nodes)
			{
				if ((int)node2.NodeType == 1)
				{
					node = node2;
					break;
				}
			}
			FindStartRoom(node);
			int num = (int)((float)(flow.Length.Min + flow.Length.Max) / 2f * RoundManager.Instance.mapSizeMultiplier * RoundManager.Instance.currentLevel.factorySizeMultiplier);
			TileCountLowerBound = (int)((float)num * Config.Singleton.MinimumTileMultiplier);
			TileCountUpperBound = (int)((float)num * Config.Singleton.MaximumTileMultiplier);
			float num2 = 0f;
			archetypes = new List<List<Archetype>>();
			flow.Lines.Sort(delegate(GraphLine x, GraphLine y)
			{
				float num5 = x.Position - y.Position;
				if (num5 == 0f)
				{
					return 0;
				}
				return (num5 > 0f) ? 1 : (-1);
			});
			foreach (GraphLine line in flow.Lines)
			{
				List<Archetype> list = new List<Archetype>();
				archetypes.Add(list);
				num2 += line.Length;
				foreach (DungeonArchetype dungeonArchetype in line.DungeonArchetypes)
				{
					Archetype archetype = new Archetype(line.Length);
					list.Add(archetype);
					float num3 = 1f / (float)dungeonArchetype.TileSets.Count;
					foreach (TileSet tileSet in dungeonArchetype.TileSets)
					{
						foreach (GameObjectChance weight2 in tileSet.TileWeights.Weights)
						{
							float num4 = (weight2.MainPathWeight + weight2.BranchPathWeight) / 2f;
							DTile component = weight2.Value.GetComponent<DTile>();
							if ((Object)(object)component == (Object)null)
							{
								Plugin.LogError("Bad dtile");
							}
							if (!((Object)(object)component == (Object)(object)StartRoom) && !(((Object)component).name == "StartRoom") && !(((Object)component).name == "ManorStartRoom"))
							{
								float weight = num3 * num4;
								archetype.AddTile(component, weight);
							}
						}
					}
				}
			}
			for (int i = 0; i < archetypes.Count; i++)
			{
				for (int j = 0; j < archetypes[i].Count; j++)
				{
					archetypes[i][j].Length /= num2;
				}
			}
		}

		private void FindStartRoom(GraphNode node)
		{
			foreach (TileSet tileSet in node.TileSets)
			{
				foreach (GameObjectChance weight in tileSet.TileWeights.Weights)
				{
					SpawnSyncedObject[] componentsInChildren = weight.Value.GetComponentsInChildren<SpawnSyncedObject>(true);
					foreach (SpawnSyncedObject val in componentsInChildren)
					{
						EntranceTeleport component = val.spawnPrefab.GetComponent<EntranceTeleport>();
						if (((component != null) ? ((Object)component).name : null) == "EntranceTeleportA")
						{
							StartRoom = weight.Value.GetComponent<DTile>();
							return;
						}
					}
				}
			}
			Plugin.LogError("Could not find a start room with an EntranceTeleportA. Defaulting to first tile we find.");
			object startRoom;
			if (node == null)
			{
				startRoom = null;
			}
			else
			{
				TileSet obj = node.TileSets[0];
				if (obj == null)
				{
					startRoom = null;
				}
				else
				{
					GameObjectChanceTable tileWeights = obj.TileWeights;
					if (tileWeights == null)
					{
						startRoom = null;
					}
					else
					{
						GameObjectChance obj2 = tileWeights.Weights[0];
						if (obj2 == null)
						{
							startRoom = null;
						}
						else
						{
							GameObject value = obj2.Value;
							startRoom = ((value != null) ? value.GetComponent<DTile>() : null);
						}
					}
				}
			}
			StartRoom = (DTile)startRoom;
		}

		public virtual (int min, int max) GetGlobalPropRange(int id)
		{
			foreach (GlobalPropSettings globalProp in flow.GlobalProps)
			{
				if (globalProp.ID == id)
				{
					return (globalProp.Count.Min, globalProp.Count.Max);
				}
			}
			Plugin.LogError($"Global Prop bounds not found for id {id}");
			return (1, 1);
		}

		public void FailedPlacementHandler(Tile tile)
		{
			if ((Object)(object)tile == (Object)null)
			{
				iterationsSinceLastSuccess++;
			}
			else
			{
				iterationsSinceLastSuccess = 0;
			}
		}

		protected IEnumerable<PlacementInfo> PlaceRoot(GameMap map)
		{
			if ((Object)(object)StartRoom == (Object)null)
			{
				Plugin.LogError("Start tile not found D:");
				yield return null;
				yield break;
			}
			if (Config.Singleton.EnableVerboseGeneration)
			{
				Plugin.LogDebug("Using '" + ((Object)StartRoom).name + "' as start room");
			}
			yield return new PlacementInfo(StartRoom);
			string startname = "";
			string name = ((Object)StartRoom).name;
			string text = name;
			string text2 = text;
			if (!(text2 == "ElevatorConnector"))
			{
				if (text2 == "Level2StartRoomConnector")
				{
					startname = "ManorStartRoom";
				}
			}
			else
			{
				startname = "StartRoom";
			}
			DTile fakestartroom = null;
			DTile[] array = Resources.FindObjectsOfTypeAll<DTile>();
			foreach (DTile t2 in array)
			{
				if (((Object)t2).name == startname)
				{
					fakestartroom = t2;
					break;
				}
			}
			if (!((Object)(object)fakestartroom != (Object)null))
			{
				yield break;
			}
			int didx;
			for (didx = 0; didx < fakestartroom.Doorways.Length && !(fakestartroom.Doorways[didx].Size == map.RootTile.Doorways[0].Size); didx++)
			{
			}
			Action<Tile> foo = delegate(Tile t)
			{
				if ((Object)(object)t == (Object)null)
				{
					Plugin.LogFatal("Failed to place start room - the map will fail to generate");
				}
			};
			map.TileInsertionEvent += foo;
			yield return new PlacementInfo(fakestartroom, didx, map.RootTile.Doorways[0]);
			map.TileInsertionEvent -= foo;
		}

		protected IEnumerable<RemovalInfo> RemoveTiles(GameMap map)
		{
			Stopwatch timer = new Stopwatch();
			timer.Start();
			Plugin.LogInfo("Removing tiles...");
			int tileCount = map.TileCount;
			int upperBound = Math.Min(TileCountUpperBound - PlacementLowerBound, tileCount);
			int lowerBound = Math.Max(4 * tileCount / 5, TileCountLowerBound);
			if (lowerBound > upperBound)
			{
				lowerBound = upperBound;
			}
			int targetCount = Rng.Next(lowerBound, upperBound + 1);
			int numTilesToDelete = tileCount - targetCount;
			if (Config.Singleton.EnableVerboseGeneration)
			{
				Plugin.LogDebug($"Removing {numTilesToDelete} tiles...");
			}
			while (numTilesToDelete > 0)
			{
				Tile[] tiles = ((Component)map).GetComponentsInChildren<Tile>();
				if (tiles.Length <= 1)
				{
					break;
				}
				Tile selected;
				int numTilesUnderSelection;
				do
				{
					selected = tiles[Rng.Next(tiles.Length)];
					numTilesUnderSelection = ((Component)selected).GetComponentsInChildren<DTile>().Length;
				}
				while (numTilesUnderSelection > numTilesToDelete);
				if (Config.Singleton.EnableVerboseGeneration)
				{
					Plugin.LogDebug("Removing " + ((Object)selected).name);
				}
				yield return new RemovalInfo(selected);
				numTilesToDelete -= numTilesUnderSelection;
			}
			timer.Stop();
			Plugin.LogDebug($"Finished removing tiles in {timer.Elapsed.TotalSeconds} seconds");
		}

		protected IEnumerable<GenerationAction> AttemptArchetypePlacement(GameMap map, Doorway root, Archetype archetype, int length, Action<int> reaction)
		{
			int progress = 0;
			using (ArchetypeRegionPlacer arp = new ArchetypeRegionPlacer(this, map, root, archetype, tilesPlaced))
			{
				int numAttempts = 0;
				while (progress != length)
				{
					PlacementInfo attempt = arp.YieldAttempt();
					if (attempt != null)
					{
						yield return attempt;
					}
					if (attempt != null && arp.iterationsSinceLastSuccess == 0)
					{
						progress++;
						if (Config.Singleton.EnableVerboseGeneration)
						{
							Plugin.LogDebug($"+ ({numAttempts}) {((Object)attempt.NewTile).name} | {((Object)attempt.AttachmentPoint.Tile).name}");
						}
					}
					else if (attempt == null)
					{
						if (!((float)progress < 0.7f * (float)length))
						{
							break;
						}
						if (Config.Singleton.EnableVerboseGeneration)
						{
							Plugin.LogDebug($"Root failure: Generated {progress}/{length} tiles from root {root.Tile}");
							if (attempt == null)
							{
								Plugin.LogDebug("Reason: Exhausted all options");
							}
							else
							{
								Plugin.LogDebug("Reason: Exceeded 30 attempts between placements");
							}
						}
						if (progress != 0)
						{
							progress = 0;
							yield return new YieldFrame();
							yield return new RemovalInfo(root.Connection.Tile);
							yield return new YieldFrame();
						}
						break;
					}
					if (Config.Singleton.EnableVerboseGeneration)
					{
						numAttempts = arp.iterationsSinceLastSuccess;
					}
				}
			}
			if (Config.Singleton.EnableVerboseGeneration)
			{
				Plugin.LogDebug($"Generated {progress}/{length} tiles from root {root.Tile}");
			}
			reaction(progress);
		}

		protected IEnumerable<GenerationAction> PlaceTiles(GameMap map)
		{
			Stopwatch timer = new Stopwatch();
			timer.Start();
			Plugin.LogInfo("Placing tiles...");
			int mapTileCount = map.TileCount;
			int lowerBound = Math.Max(mapTileCount, TileCountLowerBound);
			int target = Rng.Next(lowerBound, TileCountUpperBound + 1);
			int tile_demand = target - mapTileCount;
			tile_demand = Math.Max(tile_demand, PlacementLowerBound);
			tile_demand = Math.Min(tile_demand, PlacementUpperBound);
			if (Config.Singleton.EnableVerboseGeneration)
			{
				Plugin.LogDebug($"Queueing {tile_demand} tiles...");
			}
			int tile_demand_theory = tile_demand;
			List<(Archetype a, int len)> archetypeSizes = new List<(Archetype, int)>();
			for (int k = 0; k < archetypes.Count; k++)
			{
				Archetype archetype2 = archetypes[k][Rng.Next(archetypes[k].Count)];
				int tileCount2 = (int)(archetype2.Length * (float)tile_demand + 0.5f);
				int lower = (int)(0.9f * (float)tileCount2);
				if (lower <= 0)
				{
					lower = 1;
				}
				int upper = (int)(1.1f * (float)tileCount2);
				if (upper > tile_demand_theory)
				{
					upper = tile_demand_theory;
				}
				if (upper < lower)
				{
					break;
				}
				tileCount2 = Rng.Next(lower, upper);
				tile_demand_theory -= tileCount2;
				archetypeSizes.Add((archetype2, tileCount2));
			}
			if (tile_demand_theory != 0)
			{
				if (archetypeSizes.Count == 0)
				{
					Plugin.LogError("Was not able to select a single archetypes to generate this round");
				}
				for (int j = 0; j < archetypeSizes.Count; j++)
				{
					archetypeSizes[j] = (archetypeSizes[j].a, archetypeSizes[j].len + tile_demand_theory / archetypeSizes.Count);
				}
			}
			if (Config.Singleton.EnableVerboseGeneration)
			{
				string msg = $"Archetype sizes: ({archetypeSizes.Count}) - ";
				foreach (var item in archetypeSizes)
				{
					_ = item.a;
					int len = item.len;
					msg += $"{len}, ";
				}
				Plugin.LogDebug(msg.Substring(0, msg.Length - 2));
			}
			foreach (var item2 in archetypeSizes)
			{
				Archetype archetype = item2.a;
				int length = item2.len;
				IDoorwayManager doorwayManager = map.DoorwayManager;
				IChoice<Doorway, float> roots = doorwayManager.GetLeaves((Doorway d) => archetype.GetDoorwayCountBySize(d.Size));
				foreach (WeightedList<Doorway>.Entry entry2 in ((WeightedList<Doorway>)roots).Entries)
				{
					if ((Object)(object)entry2.item == (Object)null)
					{
						Plugin.LogError("null leaf");
						break;
					}
				}
				bool forelse = true;
				for (int i = 0; i < 50; i++)
				{
					if (roots.OpenCount == 0)
					{
						break;
					}
					Doorway root = roots.Yield(roots.OpenWidth * (float)Rng.NextDouble());
					if ((Object)(object)root == (Object)null)
					{
						Plugin.LogError("null root");
						foreach (WeightedList<Doorway>.Entry entry in ((WeightedList<Doorway>)roots).Entries)
						{
							Plugin.LogError(string.Format("{0} | {1}", ((Object)(object)entry.item == (Object)null) ? "null" : ((Object)entry.item).name, entry.weight));
						}
					}
					foreach (GenerationAction item3 in AttemptArchetypePlacement(reaction: delegate(int p)
					{
						tile_demand -= p;
						if (p != 0)
						{
							forelse = false;
						}
					}, map: map, root: root, archetype: archetype, length: length))
					{
						yield return item3;
					}
					if (!forelse)
					{
						break;
					}
					yield return new YieldFrame();
				}
				if (forelse)
				{
					Plugin.LogError($"Failed to generate an archetype of {length} tiles");
				}
			}
			Plugin.LogInfo($"Failed to place {tile_demand} tiles");
			timer.Stop();
			Plugin.LogDebug($"Finished generating tiles in {timer.Elapsed.TotalSeconds} seconds");
		}

		protected IEnumerable<ConnectionAction> HandleConnections(GameMap map)
		{
			List<ConnectionAction> list = new List<ConnectionAction>();
			foreach (ConnectAction item in ConnectTiles(map))
			{
				list.Add(item);
			}
			foreach (DisconnectAction item2 in DisconnectTiles(map))
			{
				list.Add(item2);
			}
			return list;
		}

		private IEnumerable<ConnectAction> ConnectTiles(GameMap map)
		{
			Plugin.LogInfo("Queueing making some loops...");
			foreach (Connection con in map.DoorwayManager.GetPotentialConnections((Connection c) => 1f))
			{
				if (Rng.NextDouble() < (double)DoorwayConnectionChance)
				{
					if (Config.Singleton.EnableVerboseGeneration)
					{
						Plugin.LogDebug("C " + ((Object)con.d1.Tile).name + "." + ((Object)con.d1).name + " | " + ((Object)con.d2.Tile).name + "." + ((Object)con.d2).name);
					}
					yield return new ConnectAction(con.d1, con.d2);
				}
			}
		}

		private IEnumerable<DisconnectAction> DisconnectTiles(GameMap map)
		{
			Plugin.LogInfo("Queueing removing some loops...");
			foreach (var (d1, d2) in map.DoorwayManager.GetActiveConnections((Connection c) => 1f))
			{
				if ((Object)(object)((Component)d1.Tile).transform.parent != (Object)(object)((Component)d2).transform && (Object)(object)((Component)d2.Tile).transform.parent != (Object)(object)((Component)d1).transform && Rng.NextDouble() < (double)DoorwayDisconnectChance)
				{
					if (Config.Singleton.EnableVerboseGeneration)
					{
						Plugin.LogDebug("D " + ((Object)d1.Tile).name + "." + ((Object)d1).name + " | " + ((Object)d2.Tile).name + "." + ((Object)d2).name);
					}
					yield return new DisconnectAction(d1, d2);
				}
			}
		}

		protected virtual IEnumerable<PropAction> HandleProps(DGameMap map)
		{
			Stopwatch timer = new Stopwatch();
			timer.Start();
			map.InitializeGlobalPropSets(this);
			foreach (PropAction item in HandleDoorProps(map))
			{
				yield return item;
			}
			foreach (PropAction item2 in HandleTileProps(map))
			{
				yield return item2;
			}
			foreach (PropAction item3 in HandleMapProps(map))
			{
				yield return item3;
			}
			if (Config.Singleton.ForbiddenPassages)
			{
				DDoorway[] componentsInChildren = ((Component)map).GetComponentsInChildren<DDoorway>();
				foreach (DDoorway d in componentsInChildren)
				{
					if (d.IsVacant && (Object)(object)d.ActiveRandomObject != (Object)null && Rng.Next(100) == 0)
					{
						d.ActiveRandomObject.SetActive(value: false);
					}
				}
			}
			timer.Stop();
			Plugin.LogDebug($"Finished prop handling in {timer.Elapsed.TotalSeconds} seconds");
		}

		private IEnumerable<PropAction> HandleDoorProps(DGameMap map)
		{
			if (Config.Singleton.EnableVerboseGeneration)
			{
				Plugin.LogDebug("Handling door props...");
			}
			Stopwatch timer = new Stopwatch();
			timer.Start();
			DDoorway[] doorways = ((Component)map).GetComponentsInChildren<DDoorway>();
			DDoorway[] array = doorways;
			foreach (DDoorway door in array)
			{
				if (!((Object)(object)door.ActiveRandomObject != (Object)null))
				{
					DDoorway tgt = ((door.IsVacant || Rng.Next(2) == 0) ? door : ((DDoorway)door.Connection));
					tgt.SetActiveObject((float)Rng.NextDouble());
				}
			}
			DDoorway[] array2 = doorways;
			foreach (DDoorway door2 in array2)
			{
				foreach (Prop p in door2.IsVacant ? door2.Connectors : door2.Blockers)
				{
					yield return new PropAction(p, e: false);
				}
			}
			timer.Stop();
			Plugin.LogDebug($"\tFinished door props in {timer.Elapsed.TotalSeconds} seconds");
		}

		private IEnumerable<PropAction> HandleMapProps(DGameMap map)
		{
			if (Config.Singleton.EnableVerboseGeneration)
			{
				Plugin.LogDebug("Handling global props...");
			}
			Stopwatch timer = new Stopwatch();
			timer.Start();
			foreach (PropSet propset in map.GlobalPropSets)
			{
				if (Config.Singleton.EnableVerboseGeneration)
				{
					Plugin.LogDebug("Handling propset w/ " + ((propset.Count > 0) ? ((Object)propset[0f]).name : "nothing in it") + " " + $"({propset.Count} props)");
				}
				foreach (PropAction action2 in HandlePropSetPos(propset))
				{
					if (Config.Singleton.EnableVerboseGeneration)
					{
						Plugin.LogDebug("+" + ((Object)action2.Prop).name);
					}
					yield return action2;
				}
				foreach (PropAction action in HandlePropSetNeg(propset, globalPropSet: true))
				{
					if (Config.Singleton.EnableVerboseGeneration)
					{
						Plugin.LogDebug("-" + ((Object)action.Prop).name);
					}
					yield return action;
				}
			}
			timer.Stop();
			Plugin.LogDebug($"\tFinished handling global props in {timer.Elapsed.TotalSeconds} seconds");
		}

		private IEnumerable<PropAction> HandleTileProps(DGameMap map)
		{
			if (Config.Singleton.EnableVerboseGeneration)
			{
				Plugin.LogDebug("Handling local props...");
			}
			Stopwatch timer = new Stopwatch();
			timer.Start();
			DTile[] componentsInChildren = ((Component)map).GetComponentsInChildren<DTile>();
			foreach (DTile tile in componentsInChildren)
			{
				foreach (PropSet propset2 in tile.LocalPropSets)
				{
					foreach (PropAction action2 in HandlePropSetPos(propset2))
					{
						if (Config.Singleton.EnableVerboseGeneration)
						{
							Plugin.LogDebug("+" + ((Object)action2.Prop).name);
						}
						yield return action2;
					}
				}
				foreach (PropSet propset in tile.LocalPropSets)
				{
					foreach (PropAction action in HandlePropSetNeg(propset))
					{
						if (Config.Singleton.EnableVerboseGeneration)
						{
							Plugin.LogDebug("-" + ((Object)action.Prop).name);
						}
						yield return action;
					}
				}
			}
			timer.Stop();
			Plugin.LogDebug($"\tFinished handling tile props in {timer.Elapsed.TotalSeconds} seconds");
		}

		private IEnumerable<PropAction> HandlePropSetPos(PropSet propset)
		{
			if (propset == null)
			{
				Plugin.LogException(new ArgumentNullException("propset"));
				yield break;
			}
			WeightedList<Prop> copy = new WeightedList<Prop>();
			int numActive = 0;
			int numEnable = Rng.Next(propset.Range.min, propset.Range.max + 1);
			if (numEnable > propset.Count)
			{
				numEnable = propset.Count;
			}
			foreach (var (prop, weight) in propset.Entries)
			{
				if ((Object)(object)prop == (Object)null && prop != null)
				{
					Plugin.LogError("Destroyed prop in propset");
				}
				else if (((Component)prop).gameObject.activeSelf)
				{
					numActive++;
				}
				else if (!prop.IsDoorProp)
				{
					copy.Add(prop, weight);
				}
			}
			for (int i = numActive; i < numEnable; i++)
			{
				Prop tgt;
				do
				{
					if (copy.Count == 0)
					{
						tgt = null;
						break;
					}
					tgt = copy[copy.SummedWeight * (float)Rng.NextDouble()];
					copy.Remove(tgt);
				}
				while (((Component)tgt).gameObject.activeSelf || !((Component)((Component)tgt).transform.parent).gameObject.activeInHierarchy);
				if ((Object)(object)tgt == (Object)null)
				{
					break;
				}
				yield return new PropAction(tgt, e: true);
			}
		}

		private IEnumerable<PropAction> HandlePropSetNeg(PropSet propset, bool globalPropSet = false)
		{
			if (propset == null)
			{
				Plugin.LogException(new ArgumentNullException("propset"));
				yield break;
			}
			WeightedList<Prop> copy = new WeightedList<Prop>();
			int numActive = 0;
			int numEnable = propset.Range.max;
			if (numEnable > propset.Count)
			{
				numEnable = propset.Count;
			}
			foreach (var (prop, weight) in propset.Entries)
			{
				if ((Object)(object)prop == (Object)null && prop != null)
				{
					Plugin.LogError("Destroyed prop in propset");
				}
				else if (((Component)prop).gameObject.activeInHierarchy)
				{
					numActive++;
					copy.Add(prop, weight);
				}
			}
			int i = numActive;
			while (i > numEnable && copy.Count != 0)
			{
				Prop tgt = copy[copy.SummedWeight * (float)Rng.NextDouble()];
				copy.Remove(tgt);
				yield return new PropAction(tgt, e: false);
				i--;
			}
		}

		public virtual IEnumerable<GenerationAction> Generator(GameMap m)
		{
			Stopwatch timer = new Stopwatch();
			timer.Start();
			DGameMap map = (DGameMap)m;
			if ((Object)(object)map.RootTile == (Object)null)
			{
				foreach (PlacementInfo action in PlaceRoot(map))
				{
					if (action != null)
					{
						yield return action;
						continue;
					}
					yield break;
				}
			}
			else
			{
				foreach (RemovalInfo item in RemoveTiles(map))
				{
					yield return item;
				}
			}
			yield return new YieldFrame();
			foreach (GenerationAction item2 in PlaceTiles(map))
			{
				yield return item2;
			}
			Stopwatch conTimer = new Stopwatch();
			conTimer.Start();
			foreach (ConnectionAction item3 in HandleConnections(map))
			{
				yield return item3;
			}
			conTimer.Stop();
			Plugin.LogDebug($"Finished connections in {conTimer.Elapsed.TotalSeconds} seconds");
			foreach (PropAction item4 in HandleProps(map))
			{
				yield return item4;
			}
			yield return new YieldFrame();
			timer.Stop();
			Plugin.LogDebug($"Finished generation in {timer.Elapsed.TotalSeconds} seconds");
		}
	}
	public class DDoorway : Doorway
	{
		protected List<Prop> alwaysBlockers;

		protected List<Prop> alwaysDoors;

		protected WeightedList<Prop> randomBlockerSet;

		protected WeightedList<Prop> randomDoorSet;

		protected Prop activeRandomObject = null;

		public float VerticalOffset => base.Tile.IntersectionTolerance + 0.125f;

		public Vector3 PositionOffset => ((Component)this).transform.up * VerticalOffset;

		public Prop ActiveRandomObject
		{
			get
			{
				return activeRandomObject;
			}
			protected set
			{
				activeRandomObject = value;
			}
		}

		public IEnumerable<Prop> Blockers
		{
			get
			{
				foreach (Prop alwaysBlocker in alwaysBlockers)
				{
					yield return alwaysBlocker;
				}
				foreach (Prop item in randomBlockerSet)
				{
					yield return item;
				}
			}
		}

		public IEnumerable<Prop> Connectors
		{
			get
			{
				foreach (Prop alwaysDoor in alwaysDoors)
				{
					yield return alwaysDoor;
				}
				foreach (Prop item in randomDoorSet)
				{
					yield return item;
				}
			}
		}

		public bool OwnsActiveRandomObject => (base.IsVacant ? randomBlockerSet : randomDoorSet).Contains(ActiveRandomObject);

		private void fixRotation()
		{
			//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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_0037: 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)
			Quaternion rotation = ((Component)this).transform.rotation;
			Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles;
			((Component)this).transform.rotation = Quaternion.Euler(new Vector3((float)(int)(eulerAngles.x + 0.5f), (float)(int)(eulerAngles.y + 0.5f), (float)(int)(eulerAngles.z + 0.5f)));
		}

		private Prop instantiateSubPart(GameObject o, bool isblocker)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)o == (Object)null)
			{
				return null;
			}
			if ((Object)(object)o.GetComponentInParent<Tile>(true) != (Object)(object)base.Tile)
			{
				o = Object.Instantiate<GameObject>(o);
				o.transform.SetParent(((Component)this).transform);
				o.transform.localPosition = -PositionOffset;
				o.transform.localRotation = Quaternion.identity;
			}
			Prop prop = o.GetComponent<Prop>() ?? o.AddComponent<Prop>();
			if (isblocker)
			{
				prop.IsBlocker = true;
			}
			else
			{
				prop.IsConnector = true;
			}
			return prop;
		}

		public DDoorway()
		{
			if (!((Object)(object)((Component)this).gameObject == (Object)null))
			{
				InitSize();
			}
		}

		private void Awake()
		{
			base.OnDisconnectEvent += delegate
			{
				OnDisconnect();
			};
			base.OnConnectEvent += delegate
			{
				OnConnect();
			};
		}

		public void InitSize()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Doorway component = ((Component)this).GetComponent<Doorway>();
			base.Size = component.Socket.Size;
		}

		public override void Initialize()
		{
			//IL_0048: 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)
			if (base.Initialized)
			{
				return;
			}
			base.Initialize();
			InitSize();
			fixRotation();
			if ((Object)(object)base.Tile == (Object)null)
			{
				throw new NullReferenceException("DDoorway has no parent tile. ");
			}
			Transform transform = ((Component)this).transform;
			transform.position += PositionOffset;
			Doorway component = ((Component)this).GetComponent<Doorway>();
			List<Prop> list = new List<Prop>(component.BlockerSceneObjects.Count);
			for (int i = 0; i < component.BlockerSceneObjects.Count; i++)
			{
				GameObject val = component.BlockerSceneObjects[i];
				if (!((Object)(object)val == (Object)null))
				{
					Prop prop = instantiateSubPart(val, isblocker: true);
					prop.Enable();
					list.Add(prop);
				}
			}
			alwaysBlockers = list;
			list = new List<Prop>(component.ConnectorSceneObjects.Count);
			for (int j = 0; j < component.ConnectorSceneObjects.Count; j++)
			{
				GameObject val2 = component.ConnectorSceneObjects[j];
				if (!((Object)(object)val2 == (Object)null))
				{
					Prop prop2 = instantiateSubPart(val2, isblocker: false);
					prop2.Disable();
					list.Add(prop2);
				}
			}
			alwaysDoors = list;
			randomBlockerSet = new WeightedList<Prop>(component.BlockerPrefabWeights.Count);
			foreach (GameObjectWeight blockerPrefabWeight in component.BlockerPrefabWeights)
			{
				GameObject gameObject = blockerPrefabWeight.GameObject;
				if (!((Object)(object)gameObject == (Object)null))
				{
					Prop prop3 = instantiateSubPart(gameObject, isblocker: true);
					prop3.Disable();
					randomBlockerSet.Add(prop3, blockerPrefabWeight.Weight);
				}
			}
			randomDoorSet = new WeightedList<Prop>(component.ConnectorPrefabWeights.Count);
			foreach (GameObjectWeight connectorPrefabWeight in component.ConnectorPrefabWeights)
			{
				GameObject gameObject2 = connectorPrefabWeight.GameObject;
				if (!((Object)(object)gameObject2 == (Object)null))
				{
					Prop prop4 = instantiateSubPart(gameObject2, isblocker: false);
					prop4.Disable();
					randomDoorSet.Add(prop4, connectorPrefabWeight.Weight);
				}
			}
		}

		protected bool CheckDunGenRule(TileConnectionRule rule, DDoorway other)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Invalid comparison between Unknown and I4
			CanTilesConnectDelegate @delegate = rule.Delegate;
			return @delegate == null || (int)@delegate.Invoke(((Component)base.Tile).GetComponent<Tile>(), ((Component)other.Tile).GetComponent<Tile>(), ((Component)this).GetComponent<Doorway>(), ((Component)other).GetComponent<Doorway>()) != 1;
		}

		public override bool Fits(Doorway o)
		{
			if (!(o is DDoorway other))
			{
				return false;
			}
			if (!base.Fits(other))
			{
				return false;
			}
			foreach (TileConnectionRule customConnectionRule in DoorwayPairFinder.CustomConnectionRules)
			{
				if (!CheckDunGenRule(customConnectionRule, other))
				{
					return false;
				}
			}
			return true;
		}

		protected virtual void OnConnect()
		{
			foreach (Prop alwaysBlocker in alwaysBlockers)
			{
				alwaysBlocker.Disable();
			}
			foreach (Prop alwaysDoor in alwaysDoors)
			{
				alwaysDoor.Enable();
			}
			activeRandomObject?.Disable();
			activeRandomObject = null;
		}

		public virtual void SetActiveObject(float idx)
		{
			activeRandomObject?.Disable();
			DDoorway dDoorway = (DDoorway)connection;
			if (base.IsVacant)
			{
				if (randomBlockerSet.Count == 0)
				{
					activeRandomObject = null;
				}
				else
				{
					activeRandomObject = randomBlockerSet[randomBlockerSet.SummedWeight * idx];
				}
			}
			else
			{
				if (randomDoorSet.Count == 0)
				{
					activeRandomObject = null;
					if (dDoorway.randomDoorSet.Count != 0)
					{
						dDoorway.SetActiveObject(idx);
					}
					return;
				}
				activeRandomObject = randomDoorSet[randomDoorSet.SummedWeight * idx];
			}
			activeRandomObject?.Enable();
			if ((Object)(object)dDoorway != (Object)null)
			{
				dDoorway.activeRandomObject?.Disable();
				dDoorway.activeRandomObject = activeRandomObject;
			}
		}

		public virtual void SetActiveObject(Prop prop)
		{
			activeRandomObject?.Disable();
			DDoorway dDoorway = (DDoorway)connection;
			if (base.IsVacant)
			{
				if (!randomBlockerSet.Contains(prop))
				{
					throw new ArgumentException("Provided prop '" + ((Object)prop).name + "' is not a randomBlocker of the door '" + ((Object)base.Tile).name + ":" + ((Object)this).name + "'");
				}
			}
			else if (!randomDoorSet.Contains(prop))
			{
				throw new ArgumentException("Provided prop '{prop.name}' is not a randomDoor of the door '" + ((Object)base.Tile).name + ":" + ((Object)this).name + "'");
			}
			activeRandomObject = prop;
			activeRandomObject?.Enable();
			if ((Object)(object)dDoorway != (Object)null)
			{
				dDoorway.activeRandomObject?.Disable();
				dDoorway.activeRandomObject = activeRandomObject;
			}
		}

		public virtual IList<Prop> GetProps()
		{
			List<Prop> list = new List<Prop>();
			IEnumerable<Prop> enumerable = alwaysBlockers.Concat(alwaysDoors).Concat(randomBlockerSet).Concat(randomDoorSet);
			foreach (Prop item in enumerable)
			{
				if (!list.Contains(item))
				{
					list.Add(item);
				}
			}
			return list;
		}

		protected virtual void OnDisconnect()
		{
			if ((Object)(object)this == (Object)null)
			{
				return;
			}
			foreach (Prop alwaysBlocker in alwaysBlockers)
			{
				alwaysBlocker.Enable();
			}
			foreach (Prop alwaysDoor in alwaysDoors)
			{
				alwaysDoor.Disable();
			}
			activeRandomObject?.Disable();
			activeRandomObject = null;
		}

		public bool RemoveProp(Prop p)
		{
			return alwaysBlockers.Remove(p) || alwaysDoors.Remove(p) || randomBlockerSet.Remove(p) || randomDoorSet.Remove(p);
		}
	}
	public class Prop : MonoBehaviour
	{
		public bool IsBlocker { get; set; } = false;


		public bool IsConnector { get; set; } = false;


		public bool IsTileProp { get; set; } = false;


		public bool IsMapProp { get; set; } = false;


		public bool IsDoorProp => IsBlocker || IsConnector;

		public DTile Tile => ((Component)this).GetComponentInParent<DTile>(((Component)this).gameObject.activeInHierarchy);

		public DDoorway Doorway => ((Component)this).GetComponentInParent<DDoorway>(((Component)this).gameObject.activeInHierarchy);

		public DGameMap Map => ((Component)this).GetComponentInParent<DGameMap>(((Component)this).gameObject.activeInHierarchy);

		public MonoBehaviour Parent => (MonoBehaviour)(IsDoorProp ? ((object)Doorway) : ((object)Tile));

		public void SetActive(bool value)
		{
			if (value)
			{
				Enable();
			}
			else
			{
				Disable();
			}
		}

		public virtual void Enable()
		{
			if ((Object)(object)this == (Object)null)
			{
				Plugin.LogError("Cannot enable a prop which has been destroyed");
			}
			else
			{
				((Component)this).gameObject.SetActive(true);
			}
		}

		public virtual void Disable()
		{
			if ((Object)(object)this == (Object)null)
			{
				Plugin.LogError("Cannot disable a prop which has been destroyed");
			}
			else
			{
				((Component)this).gameObject.SetActive(false);
			}
		}

		protected virtual void OnDestroy()
		{
			if (IsDoorProp)
			{
				DDoorway doorway = Doorway;
				if ((Object)(object)doorway != (Object)null)
				{
					doorway.RemoveProp(this);
				}
			}
			DTile tile = Tile;
			if ((Object)(object)tile != (Object)null)
			{
				tile.RemoveProp(this);
			}
			DGameMap map = Map;
			if ((Object)(object)map != (Object)null)
			{
				map.RemoveProp(this);
			}
		}
	}
	public class PropSet : WeightedList<Prop>
	{
		public (int min, int max) Range { get; set; } = (0, 0);


		public WeightedList<Prop> Props => this;

		public PropSet()
		{
		}

		public PropSet(LocalPropSet pset)
		{
			foreach (GameObjectChance weight in pset.Props.Weights)
			{
				if (!((Object)(object)weight.Value == (Object)null))
				{
					Prop prop = weight.Value.GetComponent<Prop>() ?? weight.Value.AddComponent<Prop>();
					prop.IsTileProp = true;
					Add(prop, (weight.MainPathWeight + weight.BranchPathWeight) / 2f);
				}
			}
			Range = (pset.PropCount.Min, pset.PropCount.Max);
		}

		public override bool Add(Prop p, float weight)
		{
			if ((Object)(object)p == (Object)null)
			{
				return false;
			}
			if (Remove(p, out var weight2))
			{
				return Add(p, weight + weight2);
			}
			return base.Add(p, weight);
		}
	}
	public class DTile : Tile
	{
		public List<Func<bool, PlacementInfo>> ValidatePlacement;

		protected List<PropSet> localPropSets;

		protected List<(Prop prop, int id, float weight)> globalProps;

		internal IList<PropSet> LocalPropSets
		{
			get
			{
				IList<PropSet> list = localPropSets?.AsReadOnly();
				return list ?? new PropSet[0];
			}
		}

		internal IList<(Prop prop, int id, float weight)> GlobalProps
		{
			get
			{
				IList<(Prop, int, float)> list = globalProps?.AsReadOnly();
				return list ?? new(Prop, int, float)[0];
			}
		}

		private Bounds DeriveBounds()
		{
			//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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_05af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due