Decompiled source of Envy v1.5.91

DoomahLevelLoader.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
using BepInEx;
using DoomahLevelLoader.UnityComponents;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[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.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("DoomahLevelLoader")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("My first plugin")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("DoomahLevelLoader")]
[assembly: AssemblyTitle("DoomahLevelLoader")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
public class OpenDiscord : MonoBehaviour
{
	public void Open()
	{
		Application.OpenURL("https://discord.gg/RY8J67neJ9");
	}
}
public class TriggerZoneBehavior : MonoBehaviour
{
	public float delay = 2f;

	public float activationDelay = 0.1f;

	private bool hasActivated = false;

	private List<Transform> ignoreList = new List<Transform>();

	private void Start()
	{
		Collider component = ((Component)this).GetComponent<Collider>();
		if ((Object)(object)component != (Object)null)
		{
			component.isTrigger = true;
		}
		DelayedInitialization();
	}

	private void DelayedInitialization()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		foreach (Transform item in ((Component)this).transform)
		{
			Transform val = item;
			((Component)val).gameObject.SetActive(false);
		}
	}

	private IEnumerator ActivateChildrenWithDelay()
	{
		bool allChildrenActivated;
		do
		{
			allChildrenActivated = true;
			foreach (Transform item in ((Component)this).transform)
			{
				Transform child = item;
				if ((Object)(object)child == (Object)null)
				{
					continue;
				}
				if (!ignoreList.Contains(child) && !((Object)child).name.Contains("Gore Zone") && !((Component)child).gameObject.activeSelf)
				{
					allChildrenActivated = false;
					if (((Object)child).name != null && (((Object)child).name != "NoPass(Clone)" || (Object)(object)((Component)child).GetComponent<AddressableReplacer>() == (Object)null))
					{
						yield return (object)new WaitForSeconds(activationDelay);
					}
					((Component)child).gameObject.SetActive(true);
					Debug.Log((object)("Trigger Activated child:  " + ((Object)child).name));
				}
				else
				{
					ignoreList.Add(child);
				}
			}
		}
		while (!allChildrenActivated);
		hasActivated = true;
	}

	private void OnTriggerEnter(Collider other)
	{
		if (((Object)((Component)other).gameObject).name == "Player" && !hasActivated)
		{
			((MonoBehaviour)this).StartCoroutine(ActivateChildrenWithDelay());
		}
	}
}
public class WaveComponent : MonoBehaviour
{
	public float checkInterval = 1f;

	private float timer = 0f;

	private float activationDelay = 0.1f;

	private bool hasActivated = false;

	private List<Transform> activatedChildren = new List<Transform>();

	private List<Transform> ignoreList = new List<Transform>();

	private void Start()
	{
		DisableAllChildren();
	}

	private void DisableAllChildren()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		foreach (Transform item in ((Component)this).transform)
		{
			Transform val = item;
			((Component)val).gameObject.SetActive(false);
		}
	}

	private void Update()
	{
		timer += Time.deltaTime;
		if (timer >= checkInterval)
		{
			timer = 0f;
			CheckChildren();
		}
	}

	private IEnumerator ActivateChildrenWithDelay(Transform[] childrenToActivate)
	{
		foreach (Transform child in childrenToActivate)
		{
			if (((Object)child).name != "NoPass(Clone)" || (Object)(object)((Component)child).GetComponent<AddressableReplacer>() == (Object)null)
			{
				((Component)child).gameObject.SetActive(true);
				yield return (object)new WaitForSeconds(activationDelay);
			}
			else
			{
				((Component)child).gameObject.SetActive(true);
			}
		}
	}

	private void CheckChildren()
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Expected O, but got Unknown
		GameObject gameObject = ((Component)((Component)this).transform.parent).gameObject;
		List<GameObject> list = new List<GameObject>();
		foreach (Transform item in ((Component)this).transform)
		{
			Transform val = item;
			list.Add(((Component)val).gameObject);
		}
		List<Transform> list2 = new List<Transform>();
		list2.AddRange(gameObject.GetComponentsInChildren<Transform>());
		list2.Remove(((Component)this).transform);
		List<Transform> list3 = new List<Transform>();
		foreach (Transform item2 in list2)
		{
			EnemyIdentifier component = ((Component)item2).GetComponent<EnemyIdentifier>();
			if ((Object)(object)component != (Object)null && !component.dead)
			{
				list3.Add(item2);
			}
			else if ((Object)(object)component != (Object)null && component.dead && list3.Contains(item2))
			{
				list3.Remove(item2);
			}
		}
		Transform[] array = (Transform[])(object)new Transform[list.Count];
		for (int i = 0; i < list.Count; i++)
		{
			array[i] = list[i].transform;
		}
		if (list3.Count == 0 && !hasActivated)
		{
			hasActivated = true;
			((MonoBehaviour)this).StartCoroutine(ActivateChildrenWithDelay(array));
		}
	}
}
public static class ShaderManager
{
	public class ShaderInfo
	{
		public string Name { get; set; }
	}

	public static Dictionary<string, Shader> shaderDictionary = new Dictionary<string, Shader>();

	private static HashSet<Material> modifiedMaterials = new HashSet<Material>();

	public static IEnumerator LoadShadersAsync()
	{
		AsyncOperationHandle<IResourceLocator> handle = Addressables.InitializeAsync();
		while (!handle.IsDone)
		{
			yield return null;
		}
		if ((int)handle.Status == 1)
		{
			IResourceLocator locator = handle.Result;
			foreach (string addressEntry in ((ResourceLocationMap)locator).Keys)
			{
				if (!addressEntry.EndsWith(".shader"))
				{
					continue;
				}
				AsyncOperationHandle<Shader> shaderHandle = Addressables.LoadAssetAsync<Shader>((object)addressEntry);
				while (!shaderHandle.IsDone)
				{
					yield return null;
				}
				if ((int)shaderHandle.Status == 1)
				{
					Shader ingameShader = shaderHandle.Result;
					if ((Object)(object)ingameShader != (Object)null && ((Object)ingameShader).name != "ULTRAKILL/PostProcessV2" && !shaderDictionary.ContainsKey(((Object)ingameShader).name))
					{
						shaderDictionary[((Object)ingameShader).name] = ingameShader;
					}
				}
				else
				{
					Debug.LogError((object)("Failed to load shader: " + shaderHandle.OperationException));
				}
			}
		}
		else
		{
			Debug.LogError((object)("Addressables initialization failed: " + handle.OperationException));
		}
	}

	public static string ModPath()
	{
		return Assembly.GetExecutingAssembly().Location.Substring(0, Assembly.GetExecutingAssembly().Location.LastIndexOf(Path.DirectorySeparatorChar));
	}

	public static IEnumerator ApplyShadersAsync(GameObject[] allGameObjects)
	{
		if (allGameObjects == null)
		{
			yield break;
		}
		foreach (GameObject go in allGameObjects)
		{
			if ((Object)(object)go == (Object)null)
			{
				continue;
			}
			Renderer[] meshRenderers = go.GetComponentsInChildren<Renderer>(true);
			Renderer[] array = meshRenderers;
			foreach (Renderer renderer in array)
			{
				if ((Object)(object)renderer == (Object)null)
				{
					continue;
				}
				Material[] newMaterials = (Material[])(object)new Material[renderer.sharedMaterials.Length];
				for (int i = 0; i < renderer.sharedMaterials.Length; i++)
				{
					Material sharedMat = (newMaterials[i] = renderer.sharedMaterials[i]);
					if (!((Object)(object)sharedMat == (Object)null) && !((Object)(object)sharedMat.shader == (Object)null) && !modifiedMaterials.Contains(sharedMat) && !(((Object)sharedMat.shader).name == "ULTRAKILL/PostProcessV2") && shaderDictionary.TryGetValue(((Object)sharedMat.shader).name, out var realShader))
					{
						newMaterials[i].shader = realShader;
						modifiedMaterials.Add(sharedMat);
						realShader = null;
					}
				}
				renderer.materials = newMaterials;
			}
			yield return null;
		}
	}

	public static IEnumerator ApplyShadersAsyncContinuously()
	{
		GameObject shaderManagerObject = new GameObject("ShaderManagerObject");
		ShaderManagerRunner shaderManagerRunner = shaderManagerObject.AddComponent<ShaderManagerRunner>();
		shaderManagerRunner.StartApplyingShaders();
		yield return null;
	}

	public static void CreateShaderDictionary()
	{
		List<ShaderInfo> list = new List<ShaderInfo>();
		Shader[] array = Resources.FindObjectsOfTypeAll<Shader>();
		foreach (Shader shader in array)
		{
			if (!list.Any((ShaderInfo s) => s.Name == ((Object)shader).name))
			{
				list.Add(new ShaderInfo
				{
					Name = ((Object)shader).name
				});
			}
		}
		string contents = JsonConvert.SerializeObject((object)list, (Formatting)1);
		File.WriteAllText(Path.Combine(ModPath(), "ShaderList.json"), contents);
	}

	public static IEnumerator LoadShadersFromDictionaryAsync()
	{
		string shaderListPath = Path.Combine(ModPath(), "ShaderList.json");
		if (!File.Exists(shaderListPath))
		{
			yield break;
		}
		Task<string> shaderDataTask = ReadAllTextAsync(shaderListPath);
		while (!shaderDataTask.IsCompleted)
		{
			yield return null;
		}
		string json = shaderDataTask.Result;
		List<ShaderInfo> shaderData = JsonConvert.DeserializeObject<List<ShaderInfo>>(json);
		Dictionary<string, Shader> shaderLookup = new Dictionary<string, Shader>();
		foreach (ShaderInfo shaderInfo in shaderData)
		{
			Shader foundShader = Shader.Find(shaderInfo.Name);
			if ((Object)(object)foundShader != (Object)null)
			{
				if (!shaderLookup.ContainsKey(shaderInfo.Name))
				{
					shaderLookup[shaderInfo.Name] = foundShader;
				}
				else
				{
					Debug.LogWarning((object)("Duplicate shader name found: " + shaderInfo.Name));
				}
			}
		}
		Material[] array = Resources.FindObjectsOfTypeAll<Material>();
		foreach (Material material in array)
		{
			if (shaderLookup.TryGetValue(((Object)material.shader).name, out var newShader) && (Object)(object)material.shader != (Object)(object)newShader)
			{
				material.shader = newShader;
			}
			newShader = null;
		}
	}

	private static async Task<string> ReadAllTextAsync(string path)
	{
		using StreamReader reader = new StreamReader(path);
		return await reader.ReadToEndAsync();
	}
}
public class ShaderManagerRunner : MonoBehaviour
{
	public void StartApplyingShaders()
	{
		((MonoBehaviour)this).StartCoroutine(ApplyShadersContinuously());
	}

	private IEnumerator ApplyShadersContinuously()
	{
		while (true)
		{
			yield return (object)new WaitForSeconds(0.15f);
			Scene activeScene = SceneManager.GetActiveScene();
			yield return ShaderManager.ApplyShadersAsync(((Scene)(ref activeScene)).GetRootGameObjects());
			yield return ShaderManager.LoadShadersFromDictionaryAsync();
		}
	}
}
namespace meshwhatever
{
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "DoomahLevelLoader";

		public const string PLUGIN_NAME = "DoomahLevelLoader";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace DoomahLevelLoader
{
	public class RefreshAndDirectory : MonoBehaviour
	{
		private static RefreshAndDirectory instance;

		public Button Refresh;

		public Button Directory;

		public static RefreshAndDirectory Instance
		{
			get
			{
				if ((Object)(object)instance == (Object)null)
				{
					instance = Object.FindObjectOfType<RefreshAndDirectory>();
					if ((Object)(object)instance == (Object)null)
					{
						Debug.LogError((object)"RefreshAndDirectory instance not found in the scene.");
					}
				}
				return instance;
			}
		}

		private void Start()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			((UnityEvent)Refresh.onClick).AddListener(new UnityAction(Refreshaction));
			((UnityEvent)Directory.onClick).AddListener(new UnityAction(DirectoryOpen));
		}

		private void Refreshaction()
		{
			Loaderscene.RefreshLevels();
		}

		private void DirectoryOpen()
		{
			Loaderscene.OpenFilesFolder();
		}
	}
	public class EnvyLoaderMenu : MonoBehaviour
	{
		private static EnvyLoaderMenu instance;

		public GameObject ContentStuff;

		public GameObject LevelsMenu;

		public GameObject LevelsButton;

		public GameObject FuckingPleaseWait;

		public TextMeshProUGUI MOTDMessage;

		private const string motdUrl = "https://raw.githubusercontent.com/SatisfiedBucket/EnvySpiteDownloader/main/motd.txt";

		public static EnvyLoaderMenu Instance
		{
			get
			{
				if ((Object)(object)instance == (Object)null)
				{
					instance = Object.FindObjectOfType<EnvyLoaderMenu>();
					if ((Object)(object)instance == (Object)null)
					{
						Debug.LogError((object)"EnvyScreen prefab not found or EnvyLoaderMenu instance not initialized.");
						return null;
					}
				}
				return instance;
			}
		}

		public void Start()
		{
			CreateLevels();
			((MonoBehaviour)this).StartCoroutine(LoadMOTD());
		}

		private IEnumerator LoadMOTD()
		{
			UnityWebRequest webRequest = UnityWebRequest.Get("https://raw.githubusercontent.com/SatisfiedBucket/EnvySpiteDownloader/main/motd.txt");
			try
			{
				yield return webRequest.SendWebRequest();
				if (webRequest.isNetworkError || webRequest.isHttpError)
				{
					Debug.LogError((object)("Failed to fetch MOTD: " + webRequest.error));
					yield break;
				}
				string motdText = webRequest.downloadHandler.text;
				if (!string.IsNullOrEmpty(motdText))
				{
					string[] lines = motdText.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
					string firstLine = ((lines.Length != 0) ? lines[0] : "No MOTD available");
					((TMP_Text)MOTDMessage).text = firstLine;
				}
			}
			finally
			{
				((IDisposable)webRequest)?.Dispose();
			}
		}

		public static void CreateLevels()
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			foreach (AssetBundleInfo assetBundle in Loaderscene.AssetBundles)
			{
				GameObject val = Object.Instantiate<GameObject>(Instance.LevelsButton, Instance.ContentStuff.transform);
				LevelButtonScript buttonScript = val.GetComponent<LevelButtonScript>();
				Loaderscene.SetLevelButtonScriptProperties(buttonScript, assetBundle);
				if (assetBundle.IsCampaign)
				{
					buttonScript.SceneToLoad = "";
				}
				if (!string.IsNullOrEmpty(buttonScript.SceneToLoad))
				{
					((UnityEvent)buttonScript.LevelButtonReal.onClick).AddListener((UnityAction)delegate
					{
						Loaderscene.LoadScene(buttonScript);
					});
				}
			}
		}

		public static void ClearContentStuffChildren()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			if ((Object)(object)Instance == (Object)null)
			{
				return;
			}
			foreach (Transform item in Instance.ContentStuff.transform)
			{
				Transform val = item;
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
		}

		public static IEnumerator UpdateLevelListingCoroutine()
		{
			Instance.FuckingPleaseWait.SetActive(true);
			ClearContentStuffChildren();
			CreateLevels();
			yield return null;
			Instance.FuckingPleaseWait.SetActive(false);
		}

		public static void UpdateLevelListing()
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((MonoBehaviour)Instance).StartCoroutine(UpdateLevelListingCoroutine());
			}
		}
	}
	public class DropdownHandler : MonoBehaviour
	{
		public TMP_Dropdown dropdown;

		private const string selectedDifficultyKey = "difficulty";

		private string settingsFilePath;

		private void Awake()
		{
			settingsFilePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "settings.json");
		}

		private void OnEnable()
		{
			int value = LoadDifficulty();
			dropdown.value = value;
			((UnityEvent<int>)(object)dropdown.onValueChanged).AddListener((UnityAction<int>)OnDropdownValueChanged);
		}

		private int LoadDifficulty()
		{
			if (File.Exists(settingsFilePath))
			{
				string text = File.ReadAllText(settingsFilePath);
				Dictionary<string, int> dictionary = JsonConvert.DeserializeObject<Dictionary<string, int>>(text);
				if (dictionary != null && dictionary.TryGetValue("difficulty", out var value))
				{
					return value;
				}
			}
			return 2;
		}

		private void SaveDifficulty(int difficulty)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int> { { "difficulty", difficulty } };
			string contents = JsonConvert.SerializeObject((object)dictionary, (Formatting)1);
			File.WriteAllText(settingsFilePath, contents);
		}

		public void OnDropdownValueChanged(int index)
		{
			SaveDifficulty(index);
		}
	}
	public class LevelButtonScript : MonoBehaviour
	{
		public Image LevelImageButtonThing;

		public Button LevelButtonReal;

		public TextMeshProUGUI NoLevel;

		public TextMeshProUGUI FileSize;

		public TextMeshProUGUI Author;

		public TextMeshProUGUI LevelName;

		[HideInInspector]
		public AssetBundle BundleName;

		[HideInInspector]
		public string SceneToLoad;

		[HideInInspector]
		public bool OpenCamp;

		private static LevelButtonScript instance;

		public static LevelButtonScript Instance
		{
			get
			{
				if (instance == null)
				{
					instance = Object.FindObjectOfType<LevelButtonScript>();
				}
				if ((Object)(object)instance == (Object)null)
				{
					Debug.LogError((object)"LevelButtonScript instance not found in the scene.");
				}
				return instance;
			}
		}
	}
	public class MenuVisibilityClass : MonoBehaviour
	{
		private static MenuVisibilityClass instance;

		public Button AssignToMenuOpenButton;

		public Button AssignToGoBackButton;

		public GameObject AssignToFuckingLevels;

		public static MenuVisibilityClass Instance
		{
			get
			{
				if ((Object)(object)instance == (Object)null)
				{
					instance = Object.FindObjectOfType<MenuVisibilityClass>();
					if ((Object)(object)instance == (Object)null)
					{
						Debug.LogError((object)"WOWZERS! SOMEONE FORGOT TO FIX THIS!");
					}
				}
				return Instance;
			}
		}

		private void Start()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			((UnityEvent)AssignToMenuOpenButton.onClick).AddListener(new UnityAction(ToggleMenu));
			((UnityEvent)AssignToGoBackButton.onClick).AddListener(new UnityAction(ToggleMenu));
		}

		private void ToggleMenu()
		{
			if (!AssignToFuckingLevels.activeSelf)
			{
				AssignToFuckingLevels.SetActive(true);
				((Component)AssignToMenuOpenButton).gameObject.SetActive(false);
				MainMenuAgony.isAgonyOpen = true;
				Debug.Log((object)"open");
			}
			else
			{
				AssignToFuckingLevels.SetActive(false);
				((Component)AssignToMenuOpenButton).gameObject.SetActive(true);
				MainMenuAgony.isAgonyOpen = false;
				Debug.Log((object)"close");
			}
		}
	}
	public static class Loader
	{
		public static AssetBundle LoadTerminal()
		{
			try
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				string name = "meshwhatever.terminal.bundle";
				using Stream stream = executingAssembly.GetManifestResourceStream(name);
				if (stream == null)
				{
					Debug.LogError((object)"Resource 'terminal.bundle' not found in embedded resources.");
					return null;
				}
				byte[] array = new byte[stream.Length];
				stream.Read(array, 0, array.Length);
				return AssetBundle.LoadFromMemory(array);
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Error loading terminal: " + ex.Message));
				return null;
			}
		}
	}
	public static class Loaderscene
	{
		public static string currentLevelName = null;

		public static string currentLevelpath = null;

		public static List<AssetBundleInfo> AssetBundles = new List<AssetBundleInfo>();

		public static string LevelsPath => Plugin.getConfigPath();

		public static string UnpackedLevelsPath
		{
			get
			{
				string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "UnpackedLevels");
				if (!Directory.Exists(text))
				{
					Directory.CreateDirectory(text);
				}
				return text;
			}
		}

		public static void LoadLevels()
		{
			Directory.GetFiles(LevelsPath, "*.doomah").ToList().ForEach(UnzipAndLoadBundles);
		}

		public static void RefreshLevels()
		{
			AssetBundles.ForEach(delegate(AssetBundleInfo bundle)
			{
				bundle.Bundle.Unload(true);
			});
			AssetBundles.Clear();
			ClearAndRecreateUnpackedLevelsFolder();
			LoadLevels();
			EnvyLoaderMenu.UpdateLevelListing();
		}

		private static void ClearAndRecreateUnpackedLevelsFolder()
		{
			string unpackedLevelsPath = UnpackedLevelsPath;
			if (Directory.Exists(unpackedLevelsPath))
			{
				Directory.Delete(unpackedLevelsPath, recursive: true);
			}
			Directory.CreateDirectory(unpackedLevelsPath);
		}

		private static void UnzipAndLoadBundles(string doomahFile)
		{
			string text = Path.Combine(UnpackedLevelsPath, Path.GetFileNameWithoutExtension(doomahFile));
			if (Directory.Exists(text))
			{
				Directory.Delete(text, recursive: true);
			}
			ZipFile.ExtractToDirectory(doomahFile, text);
			string[] files = Directory.GetFiles(text, "*.bundle");
			foreach (string bundleFile in files)
			{
				AssetBundles.Add(new AssetBundleInfo(bundleFile, text));
			}
		}

		public static void LoadScene(LevelButtonScript buttonScript)
		{
			if (!string.IsNullOrEmpty(buttonScript?.SceneToLoad))
			{
				MonoSingleton<SceneHelper>.Instance.LoadSceneAsync(buttonScript.SceneToLoad, false);
				currentLevelpath = buttonScript.SceneToLoad;
				currentLevelName = ((TMP_Text)buttonScript.LevelName).text;
				SceneHelper.ShowLoadingBlocker();
				SceneManager.LoadSceneAsync(buttonScript.SceneToLoad).completed += delegate
				{
					SceneHelper.DismissBlockers();
					Plugin.Fixorsmth();
				};
			}
		}

		public static void OpenFilesFolder()
		{
			Application.OpenURL("file://" + Plugin.getConfigPath().Replace("\\", "/"));
		}

		public static void SetLevelButtonScriptProperties(LevelButtonScript buttonScript, AssetBundleInfo bundleInfo)
		{
			//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_00d6: Unknown result type (might be due to invalid IL or missing references)
			buttonScript.BundleName = bundleInfo.Bundle;
			buttonScript.SceneToLoad = bundleInfo.ScenePaths.FirstOrDefault();
			buttonScript.OpenCamp = bundleInfo.IsCampaign;
			((TMP_Text)buttonScript.FileSize).text = bundleInfo.FileSize;
			((TMP_Text)buttonScript.Author).text = bundleInfo.Author ?? "Unknown";
			((TMP_Text)buttonScript.LevelName).text = (bundleInfo.LevelNames.Any() ? bundleInfo.LevelNames.First() : "Unnamed");
			Texture2D val = bundleInfo.LevelImages.Values.FirstOrDefault();
			if (val != null)
			{
				buttonScript.LevelImageButtonThing.sprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), Vector2.zero);
				((Graphic)buttonScript.LevelImageButtonThing).color = Color.white;
			}
			((Component)buttonScript.NoLevel).gameObject.SetActive(!bundleInfo.LevelNames.Any());
			((Component)buttonScript.LevelImageButtonThing).gameObject.SetActive(bundleInfo.LevelNames.Any());
		}

		public static bool IsSceneInAnyAssetBundle(string sceneName)
		{
			return AssetBundles.Any((AssetBundleInfo bundle) => bundle.ScenePaths.Contains(sceneName));
		}
	}
	public class AssetBundleInfo
	{
		public AssetBundle Bundle;

		public List<string> ScenePaths;

		public List<string> LevelNames;

		public Dictionary<string, Texture2D> LevelImages;

		public string FileSize;

		public string Author;

		public bool IsCampaign;

		public AssetBundleInfo(string bundleFile, string extractPath)
		{
			AssetBundleInfo assetBundleInfo = this;
			string path = Path.Combine(extractPath, "info.json");
			string path2 = Path.Combine(extractPath, "info.txt");
			LevelInfo levelInfo = (File.Exists(path) ? LevelInfo.LoadFromJson(path) : LevelInfo.LoadFromText(path2));
			Bundle = AssetBundle.LoadFromFile(bundleFile);
			IsCampaign = levelInfo?.IsCampaign ?? false;
			ScenePaths = new List<string>(levelInfo?.Scenes ?? new List<string>());
			LevelNames = levelInfo?.LevelNames ?? new List<string>();
			if (!IsCampaign && ScenePaths.Count == 0)
			{
				ExtractSceneNames();
			}
			LevelImages = LoadLevelImages(levelInfo?.LevelImages);
			FileSize = GetFileSize();
			Author = levelInfo?.Author;
			void ExtractSceneNames()
			{
				string[] allScenePaths = Bundle.GetAllScenePaths();
				foreach (string path4 in allScenePaths)
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path4);
					ScenePaths.Add(fileNameWithoutExtension);
				}
			}
			string GetFileSize()
			{
				long length = new FileInfo(bundleFile).Length;
				long num = Math.Abs(length);
				long num2 = num;
				string text;
				double num3;
				if (num2 >= 1099511627776L)
				{
					if (num2 < 1152921504606846976L)
					{
						if (num2 >= 1125899906842624L)
						{
							text = "PiB";
							num3 = length >> 40;
						}
						else
						{
							text = "TiB";
							num3 = length >> 30;
						}
					}
					else
					{
						text = "EiB";
						num3 = length >> 50;
					}
				}
				else if (num2 >= 1048576)
				{
					if (num2 >= 1073741824)
					{
						text = "GiB";
						num3 = length >> 20;
					}
					else
					{
						text = "MiB";
						num3 = length >> 10;
					}
				}
				else
				{
					if (num2 < 1024)
					{
						return length.ToString("0 B");
					}
					text = "KiB";
					num3 = length;
				}
				return (num3 / 1024.0).ToString("0.## ") + text;
			}
			Dictionary<string, Texture2D> LoadLevelImages(List<string> imagePaths)
			{
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				//IL_005a: Expected O, but got Unknown
				Dictionary<string, Texture2D> dictionary = new Dictionary<string, Texture2D>();
				if (imagePaths == null)
				{
					return dictionary;
				}
				foreach (string imagePath in imagePaths)
				{
					string path3 = Path.Combine(extractPath, imagePath);
					if (File.Exists(path3))
					{
						byte[] array = File.ReadAllBytes(path3);
						Texture2D val = new Texture2D(2, 2);
						ImageConversion.LoadImage(val, array);
						dictionary[imagePath] = val;
					}
				}
				return dictionary;
			}
		}
	}
	[Serializable]
	public class LevelInfo
	{
		public string Author;

		public string LevelName;

		public bool IsCampaign;

		public List<string> Scenes = new List<string>();

		public List<string> LevelNames = new List<string>();

		public List<string> LevelImages = new List<string>();

		public static LevelInfo LoadFromJson(string path)
		{
			return JsonUtility.FromJson<LevelInfo>(File.ReadAllText(path));
		}

		public static LevelInfo LoadFromText(string path)
		{
			if (!File.Exists(path))
			{
				return null;
			}
			LevelInfo levelInfo = new LevelInfo();
			string[] array = File.ReadAllLines(path);
			if (array.Length != 0)
			{
				levelInfo.Author = array[0].Trim();
			}
			if (array.Length > 1)
			{
				levelInfo.LevelNames.Add(array[1].Trim());
			}
			levelInfo.IsCampaign = false;
			string directoryName = Path.GetDirectoryName(path);
			string[] files = Directory.GetFiles(directoryName, "*.png");
			if (files.Length != 0)
			{
				levelInfo.LevelImages.Add(files[0]);
			}
			return levelInfo;
		}
	}
	[HarmonyPatch(typeof(SceneHelper), "RestartScene")]
	public static class SceneHelper_RestartScene_Patch
	{
		[HarmonyPrefix]
		public static bool Prefix()
		{
			if (Plugin.IsCustomLevel)
			{
				SceneManager.LoadScene(Loaderscene.currentLevelpath);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(LevelNameFinder))]
	[HarmonyPatch("OnEnable")]
	public static class LevelNameFinder_Patch
	{
		private static void Postfix(LevelNameFinder __instance)
		{
			if (Plugin.IsCustomLevel && !string.IsNullOrEmpty(Loaderscene.currentLevelName))
			{
				__instance.txt2.text = Loaderscene.currentLevelName;
			}
		}
	}
	[BepInPlugin("doomahreal.ultrakill.levelloader", "DoomahLevelLoader", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		private AssetBundle terminal;

		public static bool IsCustomLevel;

		private static Plugin _instance;

		public static Plugin Instance => _instance;

		public static string getConfigPath()
		{
			string[] array = new string[1];
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			array[0] = configPath + directorySeparatorChar + "EnvyLevels";
			return Path.Combine(array);
		}

		public static GameObject FindObjectEvenIfDisabled(string rootName, string objPath = null, int childNum = 0, bool useChildNum = false)
		{
			//IL_0003: 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)
			GameObject val = null;
			Scene activeScene = SceneManager.GetActiveScene();
			GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects();
			bool flag = false;
			GameObject[] array = rootGameObjects;
			foreach (GameObject val2 in array)
			{
				if (((Object)val2).name == rootName)
				{
					val = val2;
					flag = true;
				}
			}
			if (flag)
			{
				GameObject val3 = val;
				if (objPath != null)
				{
					val3 = ((Component)val.transform.Find(objPath)).gameObject;
					if (!useChildNum)
					{
						val = val3;
					}
				}
				if (useChildNum)
				{
					GameObject gameObject = ((Component)val3.transform.GetChild(childNum)).gameObject;
					val = gameObject;
				}
			}
			return val;
		}

		private void Awake()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			((BaseUnityPlugin)this).Logger.LogInfo((object)"If you see this, dont panick! because everything is fine :)");
			terminal = Loader.LoadTerminal();
			_instance = this;
			Harmony val = new Harmony("doomahreal.ultrakill.levelloader");
			val.PatchAll();
			if (!Directory.Exists(getConfigPath()))
			{
				Directory.CreateDirectory(getConfigPath());
			}
			SceneManager.sceneLoaded += OnSceneLoaded;
			SceneManager.sceneUnloaded += OnSceneUnloaded;
			Loaderscene.LoadLevels();
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			SceneManager.sceneUnloaded -= OnSceneUnloaded;
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			bool flag = SceneHelper.CurrentScene != "Bootstrap" && SceneHelper.CurrentScene != "Intro";
			bool mainMenu = SceneHelper.CurrentScene == "Main Menu";
			if (flag)
			{
				ShaderManager.CreateShaderDictionary();
				InstantiateEnvyScreen(mainMenu);
			}
			if (ShaderManager.shaderDictionary.Count <= 0)
			{
				((MonoBehaviour)this).StartCoroutine(ShaderManager.LoadShadersAsync());
			}
			if (Loaderscene.IsSceneInAnyAssetBundle(((Scene)(ref scene)).name))
			{
				Fixorsmth();
				return;
			}
			IsCustomLevel = false;
			Loaderscene.currentLevelName = null;
		}

		public static void Fixorsmth()
		{
			//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)
			Scene activeScene = SceneManager.GetActiveScene();
			SceneHelper.CurrentScene = ((Scene)(ref activeScene)).name;
			Camera main = Camera.main;
			IsCustomLevel = true;
			main.clearFlags = (CameraClearFlags)1;
			((MonoBehaviour)_instance).StartCoroutine(ShaderManager.ApplyShadersAsyncContinuously());
		}

		private void OnSceneUnloaded(Scene scene)
		{
			if (SceneHelper.CurrentScene == "Main Menu")
			{
				InstantiateEnvyScreen(mainMenu: true);
				ShaderManager.CreateShaderDictionary();
			}
		}

		private void InstantiateEnvyScreen(bool mainMenu)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = terminal.LoadAsset<GameObject>("EnvyScreen.prefab");
			if ((Object)(object)val == (Object)null)
			{
				Debug.LogError((object)"EnvyScreen prefab not found in the terminal bundle.");
				return;
			}
			GameObject val2 = GameObject.Find("/Canvas/Main Menu (1)");
			if (!mainMenu)
			{
				val2 = FindObjectEvenIfDisabled("Canvas", "PauseMenu");
			}
			if (!((Object)(object)val2 == (Object)null))
			{
				GameObject val3 = Object.Instantiate<GameObject>(val);
				val3.transform.SetParent(val2.transform, false);
				val3.transform.localPosition = Vector3.zero;
				val3.transform.localScale = new Vector3(1f, 1f, 1f);
			}
		}
	}
	[HarmonyPatch(typeof(Material))]
	internal static class MaterialPatches
	{
		public static void Process(Material material)
		{
			if (!((Object)(object)material.shader == (Object)null) && ShaderManager.shaderDictionary.TryGetValue(((Object)material.shader).name, out var value) && !((Object)(object)material.shader == (Object)(object)value))
			{
				material.shader = value;
			}
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPostfix]
		public static void CtorPatch1(Material __instance)
		{
			Process(__instance);
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPostfix]
		public static void CtorPatch2(Material __instance)
		{
			Process(__instance);
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPostfix]
		public static void CtorPatch3(Material __instance)
		{
			Process(__instance);
		}
	}
}
namespace DoomahLevelLoader.UnityComponents
{
	public class AddressableReplacer : MonoBehaviour
	{
		public string targetAddress;

		public bool oneTime = true;

		public bool moveToParent = true;

		public bool destroyThis = true;

		public bool IsBoss = false;

		public string BossName;

		public bool IsSanded = false;

		public bool IsPuppet = false;

		public bool IsRadient = false;

		public float RadienceTier;

		public float DamageTier;

		public float SpeedTier;

		public float HealthTier;

		internal EnemyIdentifier eid;

		private bool _activated = false;

		private void OnEnable()
		{
			Activate();
		}

		public void Activate()
		{
			//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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			if (oneTime && _activated)
			{
				return;
			}
			_activated = true;
			GameObject val = Addressables.LoadAssetAsync<GameObject>((object)targetAddress).WaitForCompletion();
			if ((Object)(object)val == (Object)null)
			{
				Debug.LogWarning((object)("Tried to load asset at address " + targetAddress + ", but it does not exist"));
				((Behaviour)this).enabled = false;
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, ((Component)this).transform.position, ((Component)this).transform.rotation, ((Component)this).transform);
			eid = val2.GetComponent<EnemyIdentifier>();
			if ((Object)(object)eid == (Object)null && val2.transform.childCount > 0)
			{
				eid = ((Component)val2.transform.GetChild(0)).GetComponent<EnemyIdentifier>();
			}
			if (moveToParent)
			{
				val2.transform.SetParent(((Component)this).transform.parent, true);
			}
			PostInstantiate(val2);
			if ((Object)(object)eid != (Object)null && IsBoss)
			{
				BossHealthBar val3 = ((Component)eid).gameObject.AddComponent<BossHealthBar>();
				if (!string.IsNullOrEmpty(BossName))
				{
					val3.bossName = BossName;
				}
			}
			if ((Object)(object)eid != (Object)null && IsSanded)
			{
				eid.Sandify(false);
			}
			if ((Object)(object)eid != (Object)null && IsPuppet)
			{
				eid.PuppetSpawn();
				eid.puppet = true;
			}
			if ((Object)(object)eid != (Object)null && IsRadient)
			{
				eid.radianceTier = RadienceTier;
				eid.healthBuffModifier = HealthTier;
				eid.speedBuffModifier = SpeedTier;
				eid.damageBuffModifier = DamageTier;
				eid.BuffAll();
			}
			if (destroyThis)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				((Component)this).gameObject.SetActive(false);
			}
			((Behaviour)this).enabled = false;
		}

		protected virtual void PostInstantiate(GameObject instantiatedObject)
		{
		}
	}
	public class CheckpointReplacer : AddressableReplacer
	{
		protected override void PostInstantiate(GameObject instantiatedObject)
		{
			Debug.Log((object)"Replacing checkpoint");
			CheckPoint componentInParent = ((Component)this).GetComponentInParent<CheckPoint>();
			CheckPoint component = instantiatedObject.GetComponent<CheckPoint>();
			foreach (Collider item in from col in instantiatedObject.GetComponentsInChildren<Collider>()
				where col.isTrigger
				select col)
			{
				Object.Destroy((Object)(object)((Component)item).gameObject);
			}
			Transform[] array = (from i in Enumerable.Range(0, instantiatedObject.transform.childCount)
				select instantiatedObject.transform.GetChild(i)).ToArray();
			foreach (Transform val in array)
			{
				Debug.Log((object)((Object)val).name);
				val.SetParent(((Component)this).transform.parent, true);
			}
			componentInParent.graphic = component.graphic;
			componentInParent.activateEffect = component.activateEffect;
		}
	}
	public class ClashTriggerDisable : MonoBehaviour
	{
		private void OnTriggerEnter(Collider other)
		{
			if (((Component)other).gameObject.tag == "Player")
			{
				MonoSingleton<PlayerTracker>.Instance.ChangeToFPS();
			}
		}
	}
	public class ClashTriggerEnable : MonoBehaviour
	{
		private bool hasenabled = false;

		public bool OnlyOnce = false;

		private void OnTriggerEnter(Collider other)
		{
			if (((Component)other).gameObject.tag == "Player" && !hasenabled)
			{
				MonoSingleton<PlayerTracker>.Instance.ChangeToPlatformer();
				if (OnlyOnce)
				{
					hasenabled = true;
				}
			}
		}
	}
	public class FinalDoorFixer : MonoBehaviour
	{
		public bool oneTime = true;

		public bool moveToParent = true;

		public BoxCollider OpenTrigger;

		private FinalDoor FD;

		private GameObject instantiatedObject;

		private bool isOpened = false;

		private bool _activated = false;

		private void OnEnable()
		{
			Activate();
		}

		public void Activate()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (oneTime && _activated)
			{
				return;
			}
			_activated = true;
			GameObject val = Addressables.LoadAssetAsync<GameObject>((object)"Assets/Prefabs/Levels/Special Rooms/FinalRoom.prefab").WaitForCompletion();
			if ((Object)(object)val == (Object)null)
			{
				Debug.LogWarning((object)"Tried to load asset, but it does not exist");
				((Behaviour)this).enabled = false;
				return;
			}
			instantiatedObject = Object.Instantiate<GameObject>(val, ((Component)this).transform.position, ((Component)this).transform.rotation, ((Component)this).transform);
			if (moveToParent)
			{
				instantiatedObject.transform.SetParent(((Component)this).transform.parent, true);
			}
			Debug.Log((object)"FinalDoorFixer: Final door game object loaded successfully.");
			Transform obj = instantiatedObject.transform.Find("FinalDoor");
			FinalDoor val2 = ((obj != null) ? ((Component)obj).GetComponent<FinalDoor>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				FD = val2;
				Debug.Log((object)"FinalDoorFixer: Final door component found successfully.");
			}
			else
			{
				Debug.LogWarning((object)"FinalDoorFixer: Final door component not found.");
			}
			PostInstantiate(instantiatedObject);
		}

		protected virtual void PostInstantiate(GameObject instantiatedObject)
		{
		}

		private void OnTriggerEnter(Collider other)
		{
			if (!isOpened && ((Component)other).CompareTag("Player") && (Object)(object)FD != (Object)null)
			{
				FD.Open();
				isOpened = true;
			}
		}
	}
	public class IdolAssigner : MonoBehaviour
	{
		public AddressableReplacer Target;

		public bool oneTime = true;

		public bool moveToParent = true;

		public bool destroyThis = true;

		private bool _activated = false;

		private void OnEnable()
		{
			Activate();
		}

		public void Activate()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (oneTime && _activated)
			{
				return;
			}
			_activated = true;
			GameObject val = Addressables.LoadAssetAsync<GameObject>((object)"Assets/Prefabs/Enemies/Idol.prefab").WaitForCompletion();
			if ((Object)(object)val == (Object)null)
			{
				Debug.LogWarning((object)"Tried to load asset, but it does not exist");
				((Behaviour)this).enabled = false;
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, ((Component)this).transform.position, ((Component)this).transform.rotation, ((Component)this).transform);
			if (moveToParent)
			{
				val2.transform.SetParent(((Component)this).transform.parent, true);
			}
			Idol component = val2.GetComponent<Idol>();
			if ((Object)(object)component != (Object)null && (Object)(object)Target != (Object)null && (Object)(object)Target.eid != (Object)null)
			{
				component.overrideTarget = Target.eid;
			}
			PostInstantiate(val2);
			if (destroyThis)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				((Component)this).gameObject.SetActive(false);
			}
			((Behaviour)this).enabled = false;
		}

		protected virtual void PostInstantiate(GameObject instantiatedObject)
		{
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		internal IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}