Decompiled source of Empress Hospital Compat Patch v2.0.0

HospitalCompatPatch.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using REPOLib;
using REPOLib.Modules;
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("Empress")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2+5f1b735e473ca4ccf3b383128fbebd889cb564da")]
[assembly: AssemblyProduct("HospitalCompatPatch")]
[assembly: AssemblyTitle("HospitalCompatPatch")]
[assembly: AssemblyVersion("1.0.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 HospitalCompatPatch
{
	[BepInPlugin("empress.repo.hospitalcompatpatch", "Empress Hospital Compat Patch", "1.0.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class HospitalCompatPatchPlugin : BaseUnityPlugin
	{
		private sealed class HospitalPrefabBuckets
		{
			private readonly HashSet<string> _startRoomNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

			private readonly HashSet<string> _normalNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

			private readonly HashSet<string> _passageNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

			private readonly HashSet<string> _deadEndNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

			private readonly HashSet<string> _extractionNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

			public List<GameObject> StartRooms { get; } = new List<GameObject>();


			public List<GameObject> Normal1 { get; } = new List<GameObject>();


			public List<GameObject> Passage1 { get; } = new List<GameObject>();


			public List<GameObject> DeadEnd1 { get; } = new List<GameObject>();


			public List<GameObject> Extraction1 { get; } = new List<GameObject>();


			public List<GameObject> Normal2 { get; } = new List<GameObject>();


			public List<GameObject> Passage2 { get; } = new List<GameObject>();


			public List<GameObject> DeadEnd2 { get; } = new List<GameObject>();


			public List<GameObject> Extraction2 { get; } = new List<GameObject>();


			public List<GameObject> Normal3 { get; } = new List<GameObject>();


			public List<GameObject> Passage3 { get; } = new List<GameObject>();


			public List<GameObject> DeadEnd3 { get; } = new List<GameObject>();


			public List<GameObject> Extraction3 { get; } = new List<GameObject>();


			public int TotalModuleCount => Normal1.Count + Passage1.Count + DeadEnd1.Count + Extraction1.Count + Normal2.Count + Passage2.Count + DeadEnd2.Count + Extraction2.Count + Normal3.Count + Passage3.Count + DeadEnd3.Count + Extraction3.Count;

			public void AddStartRoom(GameObject prefab)
			{
				AddUnique(StartRooms, _startRoomNames, prefab);
			}

			public void AddNormal(int tier, GameObject prefab)
			{
				AddByTier(tier, prefab, _normalNames, Normal1, Normal2, Normal3);
			}

			public void AddPassage(int tier, GameObject prefab)
			{
				AddByTier(tier, prefab, _passageNames, Passage1, Passage2, Passage3);
			}

			public void AddDeadEnd(int tier, GameObject prefab)
			{
				AddByTier(tier, prefab, _deadEndNames, DeadEnd1, DeadEnd2, DeadEnd3);
			}

			public void AddExtraction(int tier, GameObject prefab)
			{
				AddByTier(tier, prefab, _extractionNames, Extraction1, Extraction2, Extraction3);
			}

			private static void AddByTier(int tier, GameObject prefab, HashSet<string> names, List<GameObject> tierOne, List<GameObject> tierTwo, List<GameObject> tierThree)
			{
				switch (tier)
				{
				case 1:
					AddUnique(tierOne, names, prefab);
					break;
				case 2:
					AddUnique(tierTwo, names, prefab);
					break;
				case 3:
					AddUnique(tierThree, names, prefab);
					break;
				}
			}

			private static void AddUnique(List<GameObject> list, HashSet<string> names, GameObject prefab)
			{
				if (!((Object)(object)prefab == (Object)null) && !string.IsNullOrWhiteSpace(((Object)prefab).name) && names.Add(((Object)prefab).name))
				{
					list.Add(prefab);
				}
			}
		}

		internal const string PluginGuid = "empress.repo.hospitalcompatpatch";

		internal const string PluginName = "Empress Hospital Compat Patch";

		internal const string PluginVersion = "1.0.2";

		private const string HospitalBundleFileName = "Hospital_Level.repobundle";

		private const string HospitalLevelName = "Level - Hospital";

		private const string HospitalLevelResourcePath = "HospitalMod";

		private const float HospitalLevelPointCheckRadius = 0.5f;

		private const float HospitalLevelPointRepairRadius = 2f;

		private static readonly Regex HospitalModuleNamePattern = new Regex("^Module\\s*-\\s*Hospital\\s*-\\s*(?<type>N|P|DE|E)\\s*-\\s*(?<tier>[123])\\b", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant);

		private readonly Harmony _hospitalHarmony = new Harmony("empress.repo.hospitalcompatpatch");

		private AssetBundle? _hospitalBundle;

		private bool _hospitalRepairApplied;

		private bool _hospitalRepairQueued;

		private bool _hospitalLoggedMissingBundle;

		private bool _hospitalLoggedMissingPrefabs;

		private bool _hospitalLoggedDoorMapFallback;

		internal static HospitalCompatPatchPlugin? Instance { get; private set; }

		private void Awake()
		{
			//IL_000f: 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)
			Instance = this;
			GameObject gameObject = ((Component)this).gameObject;
			((Object)gameObject).hideFlags = (HideFlags)(((Object)gameObject).hideFlags | 0x23);
			BundleLoader.OnAllBundlesLoaded += HospitalHandleBundlesLoaded;
			_hospitalHarmony.PatchAll();
			if ((Object)(object)RunManager.instance != (Object)null)
			{
				((MonoBehaviour)this).StartCoroutine(HospitalRepairWhenReady());
			}
		}

		private void HospitalHandleBundlesLoaded()
		{
			if (!_hospitalRepairQueued && !_hospitalRepairApplied)
			{
				_hospitalRepairQueued = true;
				((MonoBehaviour)this).StartCoroutine(HospitalRepairWhenReady());
			}
		}

		private IEnumerator HospitalRepairWhenReady()
		{
			yield return null;
			for (int attempt = 0; attempt < 120; attempt++)
			{
				if (_hospitalRepairApplied)
				{
					break;
				}
				if (HospitalTryRepairLevel())
				{
					break;
				}
				yield return null;
			}
			_hospitalRepairQueued = false;
		}

		internal bool HospitalTryRepairCurrentLevel()
		{
			List<Level> list = new List<Level>();
			if ((Object)(object)LevelGenerator.Instance != (Object)null && (Object)(object)LevelGenerator.Instance.Level != (Object)null)
			{
				list.Add(LevelGenerator.Instance.Level);
			}
			if ((Object)(object)RunManager.instance != (Object)null && (Object)(object)RunManager.instance.levelCurrent != (Object)null)
			{
				list.Add(RunManager.instance.levelCurrent);
			}
			return HospitalTryRepairLevel(list);
		}

		private bool HospitalTryRepairLevel(IEnumerable<Level>? candidates = null)
		{
			if (_hospitalRepairApplied)
			{
				return true;
			}
			Level val = HospitalFindLevel(candidates) ?? HospitalFindLevel(Levels.AllLevels);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			AssetBundle val2 = HospitalGetBundle();
			if ((Object)(object)val2 == (Object)null)
			{
				if (!_hospitalLoggedMissingBundle)
				{
					_hospitalLoggedMissingBundle = true;
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Empress Hospital Compat Patch could not locate the Hospital bundle.");
				}
				return false;
			}
			_hospitalLoggedMissingBundle = false;
			HospitalPrefabBuckets hospitalPrefabBuckets = HospitalCollectPrefabs(val2);
			if (hospitalPrefabBuckets.StartRooms.Count == 0 || hospitalPrefabBuckets.TotalModuleCount == 0)
			{
				if (!_hospitalLoggedMissingPrefabs)
				{
					_hospitalLoggedMissingPrefabs = true;
					((BaseUnityPlugin)this).Logger.LogError((object)"Empress Hospital Compat Patch could not rebuild the Hospital prefab lists from the original bundle.");
				}
				return false;
			}
			_hospitalLoggedMissingPrefabs = false;
			HospitalApplyHideFlags((Object)(object)val2);
			HospitalApplyHideFlags((Object)(object)val);
			HospitalEnsureLevelFallbackData(val);
			HospitalRegisterLevelObjects(val);
			val.StartRooms = HospitalRegisterPrefabs(val, "StartRoom", hospitalPrefabBuckets.StartRooms);
			val.ModulesNormal1 = HospitalRegisterPrefabs(val, "Normal", hospitalPrefabBuckets.Normal1);
			val.ModulesPassage1 = HospitalRegisterPrefabs(val, "Passage", hospitalPrefabBuckets.Passage1);
			val.ModulesDeadEnd1 = HospitalRegisterPrefabs(val, "DeadEnd", hospitalPrefabBuckets.DeadEnd1);
			val.ModulesExtraction1 = HospitalRegisterPrefabs(val, "Extraction", hospitalPrefabBuckets.Extraction1);
			val.ModulesNormal2 = HospitalRegisterPrefabs(val, "Normal", hospitalPrefabBuckets.Normal2);
			val.ModulesPassage2 = HospitalRegisterPrefabs(val, "Passage", hospitalPrefabBuckets.Passage2);
			val.ModulesDeadEnd2 = HospitalRegisterPrefabs(val, "DeadEnd", hospitalPrefabBuckets.DeadEnd2);
			val.ModulesExtraction2 = HospitalRegisterPrefabs(val, "Extraction", hospitalPrefabBuckets.Extraction2);
			val.ModulesNormal3 = HospitalRegisterPrefabs(val, "Normal", hospitalPrefabBuckets.Normal3);
			val.ModulesPassage3 = HospitalRegisterPrefabs(val, "Passage", hospitalPrefabBuckets.Passage3);
			val.ModulesDeadEnd3 = HospitalRegisterPrefabs(val, "DeadEnd", hospitalPrefabBuckets.DeadEnd3);
			val.ModulesExtraction3 = HospitalRegisterPrefabs(val, "Extraction", hospitalPrefabBuckets.Extraction3);
			_hospitalRepairApplied = val.StartRooms.Count > 0 && HospitalCountModules(val) > 0;
			if (_hospitalRepairApplied)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"Empress Hospital Compat Patch repaired {((Object)val).name} with {val.StartRooms.Count} start rooms and {HospitalCountModules(val)} modules.");
			}
			return _hospitalRepairApplied;
		}

		private static Level? HospitalFindLevel(IEnumerable<Level>? candidates)
		{
			if (candidates == null)
			{
				return null;
			}
			foreach (Level candidate in candidates)
			{
				if (!HospitalIsHospitalLevel(candidate))
				{
					continue;
				}
				return candidate;
			}
			return null;
		}

		private AssetBundle? HospitalGetBundle()
		{
			if ((Object)(object)_hospitalBundle != (Object)null)
			{
				return _hospitalBundle;
			}
			foreach (AssetBundle allLoadedAssetBundle in AssetBundle.GetAllLoadedAssetBundles())
			{
				try
				{
					if (allLoadedAssetBundle.GetAllAssetNames().Any((string assetName) => assetName.EndsWith("level - hospital.asset", StringComparison.OrdinalIgnoreCase) || assetName.EndsWith("hospitallevelcontent.asset", StringComparison.OrdinalIgnoreCase)))
					{
						_hospitalBundle = allLoadedAssetBundle;
						return _hospitalBundle;
					}
				}
				catch
				{
				}
			}
			string text = Directory.GetFiles(Paths.PluginPath, "Hospital_Level.repobundle", SearchOption.AllDirectories).FirstOrDefault();
			if (string.IsNullOrWhiteSpace(text))
			{
				return null;
			}
			_hospitalBundle = AssetBundle.LoadFromFile(text);
			return _hospitalBundle;
		}

		private static HospitalPrefabBuckets HospitalCollectPrefabs(AssetBundle bundle)
		{
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			HospitalPrefabBuckets hospitalPrefabBuckets = new HospitalPrefabBuckets();
			StartRoom[] array = bundle.LoadAllAssets<StartRoom>();
			foreach (StartRoom val in array)
			{
				HospitalTryBucketPrefab(hospitalPrefabBuckets, ((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null);
			}
			Module[] array2 = bundle.LoadAllAssets<Module>();
			foreach (Module val2 in array2)
			{
				HospitalTryBucketPrefab(hospitalPrefabBuckets, ((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject : null);
			}
			GameObject[] array3 = bundle.LoadAllAssets<GameObject>();
			foreach (GameObject prefab in array3)
			{
				HospitalTryBucketPrefab(hospitalPrefabBuckets, prefab);
			}
			if (hospitalPrefabBuckets.StartRooms.Count == 0 || hospitalPrefabBuckets.TotalModuleCount == 0)
			{
				StartRoom[] array4 = Resources.FindObjectsOfTypeAll<StartRoom>();
				Scene scene;
				foreach (StartRoom val3 in array4)
				{
					if (!((Object)(object)val3 == (Object)null))
					{
						scene = ((Component)val3).gameObject.scene;
						if (!((Scene)(ref scene)).IsValid())
						{
							HospitalTryBucketPrefab(hospitalPrefabBuckets, ((Component)val3).gameObject);
						}
					}
				}
				Module[] array5 = Resources.FindObjectsOfTypeAll<Module>();
				foreach (Module val4 in array5)
				{
					if (!((Object)(object)val4 == (Object)null))
					{
						scene = ((Component)val4).gameObject.scene;
						if (!((Scene)(ref scene)).IsValid())
						{
							HospitalTryBucketPrefab(hospitalPrefabBuckets, ((Component)val4).gameObject);
						}
					}
				}
			}
			return hospitalPrefabBuckets;
		}

		private static void HospitalTryBucketPrefab(HospitalPrefabBuckets buckets, GameObject? prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return;
			}
			string text = ((Object)prefab).name ?? string.Empty;
			if (text.StartsWith("Start Room - Hospital -", StringComparison.OrdinalIgnoreCase))
			{
				buckets.AddStartRoom(prefab);
				return;
			}
			Match match = HospitalModuleNamePattern.Match(text);
			if (match.Success && int.TryParse(match.Groups["tier"].Value, out var result))
			{
				switch (match.Groups["type"].Value.ToUpperInvariant())
				{
				case "N":
					buckets.AddNormal(result, prefab);
					break;
				case "P":
					buckets.AddPassage(result, prefab);
					break;
				case "DE":
					buckets.AddDeadEnd(result, prefab);
					break;
				case "E":
					buckets.AddExtraction(result, prefab);
					break;
				}
			}
		}

		private static void HospitalRegisterLevelObjects(Level level)
		{
			if (level.ConnectObject != null)
			{
				GameObject val = HospitalResolvePrefab(level.ConnectObject);
				if ((Object)(object)val != (Object)null)
				{
					HospitalApplyHideFlags((Object)(object)val);
					Utilities.FixAudioMixerGroups(val);
					NetworkPrefabs.RegisterNetworkPrefab("Level/" + HospitalGetLevelPath(level) + "/Other/" + HospitalGetPrefabName(level.ConnectObject, val), val);
				}
			}
			if (level.BlockObject != null)
			{
				GameObject val2 = HospitalResolvePrefab(level.BlockObject);
				if ((Object)(object)val2 != (Object)null)
				{
					HospitalApplyHideFlags((Object)(object)val2);
					Utilities.FixAudioMixerGroups(val2);
					NetworkPrefabs.RegisterNetworkPrefab("Level/" + HospitalGetLevelPath(level) + "/Other/" + HospitalGetPrefabName(level.BlockObject, val2), val2);
				}
			}
		}

		private static string HospitalGetLevelPath(Level level)
		{
			return string.IsNullOrWhiteSpace(((Object)level).name) ? "HospitalMod" : ((Object)level).name;
		}

		private static string HospitalGetPrefabName(PrefabRef prefabRef, GameObject prefab)
		{
			return string.IsNullOrWhiteSpace(prefabRef.PrefabName) ? ((Object)prefab).name : prefabRef.PrefabName;
		}

		private static GameObject? HospitalResolvePrefab(PrefabRef? prefabRef)
		{
			if (prefabRef == null)
			{
				return null;
			}
			if (prefabRef.IsValid())
			{
				return prefabRef.Prefab;
			}
			AssetBundle bundle = prefabRef.Bundle;
			if ((Object)(object)bundle == (Object)null || string.IsNullOrWhiteSpace(prefabRef.PrefabName))
			{
				return null;
			}
			GameObject[] array = bundle.LoadAllAssets<GameObject>();
			foreach (GameObject val in array)
			{
				if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, prefabRef.PrefabName, StringComparison.OrdinalIgnoreCase))
				{
					return val;
				}
			}
			return null;
		}

		private static List<PrefabRef> HospitalRegisterPrefabs(Level level, string moduleTypeName, IEnumerable<GameObject> prefabs)
		{
			List<PrefabRef> list = new List<PrefabRef>();
			foreach (GameObject item in prefabs.OrderBy<GameObject, string>((GameObject gameObject) => ((Object)gameObject).name, StringComparer.OrdinalIgnoreCase))
			{
				HospitalApplyHideFlags((Object)(object)item);
				Utilities.FixAudioMixerGroups(item);
				string text = "Level/" + ((Object)level).name + "/" + moduleTypeName + "/" + ((Object)item).name;
				PrefabRef val = NetworkPrefabs.RegisterNetworkPrefab(text, item);
				if (val != null)
				{
					list.Add(val);
				}
			}
			return list;
		}

		private static int HospitalCountModules(Level level)
		{
			return (level.ModulesNormal1?.Count ?? 0) + (level.ModulesPassage1?.Count ?? 0) + (level.ModulesDeadEnd1?.Count ?? 0) + (level.ModulesExtraction1?.Count ?? 0) + (level.ModulesNormal2?.Count ?? 0) + (level.ModulesPassage2?.Count ?? 0) + (level.ModulesDeadEnd2?.Count ?? 0) + (level.ModulesExtraction2?.Count ?? 0) + (level.ModulesNormal3?.Count ?? 0) + (level.ModulesPassage3?.Count ?? 0) + (level.ModulesDeadEnd3?.Count ?? 0) + (level.ModulesExtraction3?.Count ?? 0);
		}

		internal static bool HospitalIsCurrentLevel()
		{
			return HospitalIsHospitalLevel(((Object)(object)LevelGenerator.Instance != (Object)null) ? LevelGenerator.Instance.Level : null) || HospitalIsHospitalLevel(((Object)(object)RunManager.instance != (Object)null) ? RunManager.instance.levelCurrent : null);
		}

		private static bool HospitalIsHospitalLevel(Level? level)
		{
			if ((Object)(object)level == (Object)null)
			{
				return false;
			}
			return string.Equals(((Object)level).name, "Level - Hospital", StringComparison.OrdinalIgnoreCase) || string.Equals(((Object)level).name, "HospitalMod", StringComparison.OrdinalIgnoreCase) || (!string.IsNullOrWhiteSpace(((Object)level).name) && ((Object)level).name.IndexOf("hospital", StringComparison.OrdinalIgnoreCase) >= 0) || (!string.IsNullOrWhiteSpace(level.NarrativeName) && level.NarrativeName.IndexOf("hospital", StringComparison.OrdinalIgnoreCase) >= 0);
		}

		internal static void HospitalEnsureLevelFallbackData(Level? level)
		{
			if (HospitalIsHospitalLevel(level))
			{
				Level val = level;
				if (val.ValuablePresets == null)
				{
					val.ValuablePresets = new List<LevelValuables>();
				}
				val = level;
				if (val.AmbiencePresets == null)
				{
					val.AmbiencePresets = new List<LevelAmbience>();
				}
				if (level.ValuablePresets.Count == 0 && (Object)(object)ValuablePresets.GenericValuablePreset != (Object)null)
				{
					level.ValuablePresets.Add(ValuablePresets.GenericValuablePreset);
				}
				if (level.AmbiencePresets.Count == 0 && HospitalTryGetFallbackAmbience(out LevelAmbience ambience))
				{
					level.AmbiencePresets.Add(ambience);
				}
			}
		}

		private static bool HospitalTryGetFallbackAmbience(out LevelAmbience ambience)
		{
			ambience = null;
			if ((Object)(object)AudioManager.instance != (Object)null && AudioManager.instance.levelAmbiences != null)
			{
				foreach (LevelAmbience levelAmbience in AudioManager.instance.levelAmbiences)
				{
					if ((Object)(object)levelAmbience == (Object)null)
					{
						continue;
					}
					ambience = levelAmbience;
					return true;
				}
			}
			if ((Object)(object)RunManager.instance != (Object)null && RunManager.instance.levels != null)
			{
				foreach (Level level in RunManager.instance.levels)
				{
					if (level?.AmbiencePresets == null)
					{
						continue;
					}
					foreach (LevelAmbience ambiencePreset in level.AmbiencePresets)
					{
						if ((Object)(object)ambiencePreset == (Object)null)
						{
							continue;
						}
						ambience = ambiencePreset;
						return true;
					}
				}
			}
			return false;
		}

		internal static void HospitalEnsureExtractionPointCompatibility(ExtractionPoint extractionPoint)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			if ((Object)(object)extractionPoint == (Object)null || !HospitalIsCurrentLevel())
			{
				return;
			}
			if ((Object)(object)extractionPoint.extractionArea == (Object)null)
			{
				GameObject val = GameObject.CreatePrimitive((PrimitiveType)2);
				((Object)val).name = "Hospital Patch Extraction Area";
				val.transform.SetParent(((Component)extractionPoint).transform, false);
				val.transform.localPosition = Vector3.zero;
				val.transform.localRotation = Quaternion.identity;
				val.transform.localScale = Vector3.one * 0.1f;
				MeshRenderer component = val.GetComponent<MeshRenderer>();
				if ((Object)(object)component != (Object)null)
				{
					((Renderer)component).enabled = false;
				}
				Collider component2 = val.GetComponent<Collider>();
				if ((Object)(object)component2 != (Object)null)
				{
				}
				val.SetActive(false);
				HospitalApplyHideFlags((Object)(object)val);
				extractionPoint.extractionArea = val;
			}
			if ((Object)(object)extractionPoint.grossUp == (Object)null)
			{
				GameObject val2 = new GameObject("Hospital Patch GrossUp");
				val2.transform.SetParent(((Component)extractionPoint).transform, false);
				val2.SetActive(false);
				HospitalApplyHideFlags((Object)(object)val2);
				extractionPoint.grossUp = val2;
			}
		}

		internal void HospitalRepairLevelPoints(LevelGenerator levelGenerator)
		{
			if ((Object)(object)levelGenerator == (Object)null || !HospitalIsHospitalLevel(levelGenerator.Level) || levelGenerator.LevelPathPoints == null)
			{
				return;
			}
			int num = 0;
			foreach (LevelPoint levelPathPoint in levelGenerator.LevelPathPoints)
			{
				if (HospitalRepairLevelPoint(levelPathPoint))
				{
					num++;
				}
			}
			if (num > 0)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"Empress Hospital Compat Patch repaired {num} Hospital level points onto the navmesh.");
			}
		}

		private static bool HospitalRepairLevelPoint(LevelPoint? levelPoint)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)levelPoint == (Object)null)
			{
				return false;
			}
			Vector3 position = ((Component)levelPoint).transform.position;
			NavMeshHit val = default(NavMeshHit);
			if (NavMesh.SamplePosition(position, ref val, 0.5f, -1))
			{
				return false;
			}
			NavMeshHit val2 = default(NavMeshHit);
			if (!NavMesh.SamplePosition(position, ref val2, 2f, -1))
			{
				return false;
			}
			((Component)levelPoint).transform.position = ((NavMeshHit)(ref val2)).position;
			RoomVolume room = default(RoomVolume);
			Vector3 val3 = default(Vector3);
			if ((Object)(object)levelPoint.Room == (Object)null && SemiFunc.GetRoomVolumeAtPosition(((NavMeshHit)(ref val2)).position, ref room, ref val3))
			{
				levelPoint.Room = room;
			}
			return true;
		}

		internal GameObject HospitalCreateFallbackDoorMapObject(Map map, DirtFinderMapDoor door)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			MapLayer layerParent = map.GetLayerParent(((Component)door).transform.position.y);
			GameObject val = HospitalInstantiateFallbackDoorMapObject(map, ((Component)layerParent).transform);
			((Object)val).name = ((Object)((Component)door).gameObject).name;
			door.Target = val.transform;
			DirtFinderMapDoorTarget val2 = val.GetComponent<DirtFinderMapDoorTarget>() ?? val.AddComponent<DirtFinderMapDoorTarget>();
			val2.Target = ((Component)door).transform;
			val2.Layer = layerParent;
			DirtFinderMapDoorTarget val3 = val2;
			if (val3.HingeTransform == null)
			{
				val3.HingeTransform = val.transform;
			}
			map.DoorUpdate(val2.HingeTransform, ((Component)door).transform, layerParent);
			if (!_hospitalLoggedDoorMapFallback)
			{
				_hospitalLoggedDoorMapFallback = true;
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Empress Hospital Compat Patch injected fallback minimap door markers for missing Hospital door prefabs.");
			}
			return val;
		}

		private static GameObject HospitalInstantiateFallbackDoorMapObject(Map map, Transform parent)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			GameObject val;
			if ((Object)(object)map.Door1x1Object != (Object)null)
			{
				val = Object.Instantiate<GameObject>(map.Door1x1Object, parent);
				Collider[] componentsInChildren = val.GetComponentsInChildren<Collider>(true);
				foreach (Collider val2 in componentsInChildren)
				{
				}
			}
			else
			{
				val = GameObject.CreatePrimitive((PrimitiveType)3);
				val.transform.SetParent(parent, false);
				val.transform.localScale = new Vector3(0.12f, 0.12f, 0.3f);
				Collider component = val.GetComponent<Collider>();
				if (!((Object)(object)component != (Object)null))
				{
				}
			}
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.identity;
			DirtFinderMapDoorTarget val3 = val.GetComponent<DirtFinderMapDoorTarget>() ?? val.AddComponent<DirtFinderMapDoorTarget>();
			DirtFinderMapDoorTarget val4 = val3;
			if (val4.HingeTransform == null)
			{
				val4.HingeTransform = val.transform;
			}
			HospitalApplyHideFlags((Object)(object)val);
			return val;
		}

		private static void HospitalApplyHideFlags(Object obj)
		{
			//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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: 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)
			if (obj == (Object)null)
			{
				return;
			}
			obj.hideFlags = (HideFlags)(obj.hideFlags | 0x23);
			GameObject val = (GameObject)(object)((obj is GameObject) ? obj : null);
			if (val == null)
			{
				return;
			}
			Transform[] componentsInChildren = val.GetComponentsInChildren<Transform>(true);
			foreach (Transform val2 in componentsInChildren)
			{
				((Object)val2).hideFlags = (HideFlags)(((Object)val2).hideFlags | 0x23);
				GameObject gameObject = ((Component)val2).gameObject;
				((Object)gameObject).hideFlags = (HideFlags)(((Object)gameObject).hideFlags | 0x23);
				Component[] components = ((Component)val2).GetComponents<Component>();
				foreach (Component val3 in components)
				{
					if ((Object)(object)val3 != (Object)null)
					{
						((Object)val3).hideFlags = (HideFlags)(((Object)val3).hideFlags | 0x23);
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(LevelGenerator), "StartRoomGeneration")]
	internal static class HospitalCompatPatchStartRoomGenerationPatch
	{
		[HarmonyPrefix]
		private static void HospitalPrefix()
		{
			HospitalCompatPatchPlugin.Instance?.HospitalTryRepairCurrentLevel();
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint), "Start")]
	internal static class HospitalCompatPatchExtractionPointStartPatch
	{
		[HarmonyPostfix]
		private static void HospitalPostfix(ExtractionPoint __instance)
		{
			HospitalCompatPatchPlugin.HospitalEnsureExtractionPointCompatibility(__instance);
		}
	}
	[HarmonyPatch(typeof(Levels), "RegisterLevelWithGame")]
	internal static class HospitalCompatPatchRegisterLevelPatch
	{
		[HarmonyPrefix]
		private static void HospitalPrefix(Level level)
		{
			HospitalCompatPatchPlugin.HospitalEnsureLevelFallbackData(level);
		}
	}
	[HarmonyPatch(typeof(Map), "AddDoor")]
	internal static class HospitalCompatPatchMapAddDoorPatch
	{
		[HarmonyPrefix]
		private static bool HospitalPrefix(Map __instance, DirtFinderMapDoor door, GameObject doorPrefab, ref GameObject __result)
		{
			if (!HospitalCompatPatchPlugin.HospitalIsCurrentLevel() || (Object)(object)door == (Object)null || (Object)(object)doorPrefab != (Object)null)
			{
				return true;
			}
			HospitalCompatPatchPlugin instance = HospitalCompatPatchPlugin.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return true;
			}
			__result = instance.HospitalCreateFallbackDoorMapObject(__instance, door);
			return false;
		}
	}
	[HarmonyPatch(typeof(LevelGenerator), "NavMeshSetupRPC")]
	internal static class HospitalCompatPatchNavMeshSetupPatch
	{
		[HarmonyPostfix]
		private static void HospitalPostfix(LevelGenerator __instance)
		{
			HospitalCompatPatchPlugin.Instance?.HospitalRepairLevelPoints(__instance);
		}
	}
}