Decompiled source of WhereToDie v1.0.0

WhereToDie.dll

Decompiled a day ago
using System;
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 BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using EntityStates;
using EntityStates.Interactables.MSObelisk;
using EntityStates.Missions.ProvidenceBossEncounter;
using HG.Reflection;
using Microsoft.CodeAnalysis;
using On.EntityStates.Interactables.MSObelisk;
using On.EntityStates.Missions.ProvidenceBossEncounter;
using On.RoR2;
using On.RoR2.UI;
using RiskOfOptions;
using RiskOfOptions.Options;
using RoR2;
using RoR2.Items;
using RoR2.Navigation;
using RoR2.Networking;
using RoR2.UI;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("WhereToDie")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+8a664683e9d91851865687b40b023fdcc7deefeb")]
[assembly: AssemblyProduct("WhereToDie")]
[assembly: AssemblyTitle("WhereToDie")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace WhereToDie
{
	internal static class AuroraRenderer
	{
		private const string ShrineAddress = "RoR2/DLC4/HallowingShrineBase.prefab";

		private const string BeamName = "Beam";

		private const float PrefabRadius = 8.2f;

		private const float StageCellSize = 220f;

		private const int MaxStageAuroras = 9;

		private const float StageAuroraScale = 2.5f;

		private const float StageEmissionMultiplier = 0.2f;

		private static readonly Color DeathColor = new Color(1f, 0.16f, 0.1f, 1f);

		private static GameObject beamPrefab;

		private static Vector3 beamOffset;

		private static Quaternion beamRotation;

		private static readonly Dictionary<string, AuroraFader> instances = new Dictionary<string, AuroraFader>();

		private static readonly HashSet<string> wanted = new HashSet<string>();

		private static bool dirty = true;

		private static bool shown;

		private static readonly Dictionary<Texture, Texture2D> deathRamps = new Dictionary<Texture, Texture2D>();

		internal static void Init()
		{
			//IL_0005: 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)
			AsyncOperationHandle<GameObject> val = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/DLC4/HallowingShrineBase.prefab");
			val.Completed += delegate(AsyncOperationHandle<GameObject> handle)
			{
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_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)
				//IL_0083: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0093: Unknown result type (might be due to invalid IL or missing references)
				GameObject result = handle.Result;
				Transform val2 = (Object.op_Implicit((Object)(object)result) ? ((IEnumerable<Transform>)result.GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "Beam")) : null);
				if (!Object.op_Implicit((Object)(object)val2))
				{
					WhereToDiePlugin.Log.LogError((object)"'Beam' not found in RoR2/DLC4/HallowingShrineBase.prefab; the hallowed aurora is disabled.");
				}
				else
				{
					beamPrefab = ((Component)val2).gameObject;
					beamOffset = result.transform.InverseTransformPoint(val2.position);
					beamRotation = Quaternion.Inverse(result.transform.rotation) * val2.rotation;
					dirty = true;
				}
			};
			ZoneTracker.onMarkersChanged += delegate
			{
				dirty = true;
			};
			WhereToDiePlugin.HallowedAurora.SettingChanged += delegate
			{
				dirty = true;
			};
			RoR2Application.onUpdate += Update;
		}

		private static void Update()
		{
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			bool flag = WhereToDiePlugin.HallowedAurora.Value && Object.op_Implicit((Object)(object)beamPrefab) && LocalPlayerHasUnusedPage();
			if (flag != shown)
			{
				shown = flag;
				dirty = true;
			}
			foreach (string item in (from pair in instances
				where !Object.op_Implicit((Object)(object)pair.Value)
				select pair.Key).ToList())
			{
				instances.Remove(item);
			}
			if (!dirty)
			{
				return;
			}
			dirty = false;
			wanted.Clear();
			if (flag)
			{
				foreach (ZoneMarker marker in ZoneTracker.Markers)
				{
					if (marker.StageWide)
					{
						SpawnStageWide(marker);
					}
					else
					{
						Spawn(marker.Position, Mathf.Clamp(marker.Radius / 8.2f, 0.6f, 8f), marker.Dies, 1f);
					}
				}
			}
			foreach (string item2 in instances.Keys.Where((string key) => !wanted.Contains(key)).ToList())
			{
				instances[item2].FadeOutAndDestroy();
				instances.Remove(item2);
			}
		}

		internal static bool LocalPlayerHasUnusedPage()
		{
			LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
			CharacterBody val = ((firstLocalUser != null) ? firstLocalUser.cachedBody : null);
			ItemDef pageDie = Items.PageDie;
			if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.inventory) && Object.op_Implicit((Object)(object)pageDie))
			{
				return val.inventory.GetItemCountEffective(pageDie) > 0;
			}
			return false;
		}

		private static void SpawnStageWide(ZoneMarker marker)
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			NodeGraph val = (Object.op_Implicit((Object)(object)SceneInfo.instance) ? SceneInfo.instance.groundNodes : null);
			Dictionary<Vector2Int, Vector3> dictionary = new Dictionary<Vector2Int, Vector3>();
			if (Object.op_Implicit((Object)(object)val))
			{
				int nodeCount = val.GetNodeCount();
				Vector3 val2 = default(Vector3);
				Vector2Int key = default(Vector2Int);
				for (int i = 0; i < nodeCount; i++)
				{
					if (val.GetNodePosition(new NodeIndex(i), ref val2))
					{
						((Vector2Int)(ref key))..ctor(Mathf.FloorToInt(val2.x / 220f), Mathf.FloorToInt(val2.z / 220f));
						if (!dictionary.TryGetValue(key, out var value) || val2.y > value.y)
						{
							dictionary[key] = val2;
						}
					}
				}
			}
			if (dictionary.Count == 0)
			{
				Spawn(marker.Position, 2.5f, marker.Dies, 0.2f);
				return;
			}
			Random random = new Random(Object.op_Implicit((Object)(object)SceneCatalog.mostRecentSceneDef) ? SceneCatalog.mostRecentSceneDef.cachedName.GetHashCode() : 0);
			foreach (Vector3 item in dictionary.Values.OrderBy((Vector3 _) => random.Next()).Take(9))
			{
				Vector3 val3 = new Vector3((float)random.NextDouble() - 0.5f, 0f, (float)random.NextDouble() - 0.5f) * 88f;
				Spawn(scale: 2.5f * (0.7f + 0.6f * (float)random.NextDouble()), position: item + val3, dies: marker.Dies, emissionMultiplier: 0.2f);
			}
		}

		private static void Spawn(Vector3 position, float scale, bool dies, float emissionMultiplier)
		{
			//IL_000d: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: 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_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: 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_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: 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)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			string text = $"{position.x:0.0},{position.y:0.0},{position.z:0.0}|{scale:0.00}|{dies}|{emissionMultiplier:0.00}";
			wanted.Add(text);
			if (instances.ContainsKey(text))
			{
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(beamPrefab, position + beamOffset * scale, beamRotation);
			((Object)val).name = "WhereToDie_Aurora";
			val.transform.localScale = Vector3.one * scale;
			ParticleSystem[] componentsInChildren = val.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem obj in componentsInChildren)
			{
				obj.Stop(false, (ParticleSystemStopBehavior)0);
				MainModule main = obj.main;
				((MainModule)(ref main)).loop = true;
				((MainModule)(ref main)).scalingMode = (ParticleSystemScalingMode)0;
				MinMaxCurve startLifetime = ((MainModule)(ref main)).startLifetime;
				if (((MinMaxCurve)(ref startLifetime)).constantMax > ((MainModule)(ref main)).duration)
				{
					startLifetime = ((MainModule)(ref main)).startLifetime;
					((MainModule)(ref main)).duration = Mathf.Max(1f, ((MinMaxCurve)(ref startLifetime)).constantMax * 0.5f);
				}
				if (dies)
				{
					MinMaxGradient startColor = ((MainModule)(ref main)).startColor;
					((MainModule)(ref main)).startColor = new MinMaxGradient(Tint(((MinMaxGradient)(ref startColor)).color));
				}
				EmissionModule emission = obj.emission;
				((EmissionModule)(ref emission)).rateOverTimeMultiplier = ((EmissionModule)(ref emission)).rateOverTimeMultiplier * emissionMultiplier;
				ParticleSystemRenderer component = ((Component)obj).GetComponent<ParticleSystemRenderer>();
				if (dies && Object.op_Implicit((Object)(object)component))
				{
					Material[] materials = ((Renderer)component).materials;
					for (int j = 0; j < materials.Length; j++)
					{
						TintMaterial(materials[j]);
					}
				}
			}
			AuroraFader value = val.AddComponent<AuroraFader>();
			componentsInChildren = val.GetComponentsInChildren<ParticleSystem>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].Play(false);
			}
			instances[text] = value;
		}

		private static Color Tint(Color color)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(new float[3] { color.r, color.g, color.b });
			return new Color(DeathColor.r * num, DeathColor.g * num, DeathColor.b * num, color.a);
		}

		private static void TintMaterial(Material material)
		{
			//IL_0016: 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)
			if (!Object.op_Implicit((Object)(object)material))
			{
				return;
			}
			Shader shader = material.shader;
			for (int i = 0; i < shader.GetPropertyCount(); i++)
			{
				if ((int)shader.GetPropertyType(i) == 0)
				{
					int propertyNameId = shader.GetPropertyNameId(i);
					material.SetColor(propertyNameId, Tint(material.GetColor(propertyNameId)));
				}
			}
			if (!material.HasProperty("_RemapTex"))
			{
				return;
			}
			Texture texture = material.GetTexture("_RemapTex");
			if (texture != null && Object.op_Implicit((Object)(object)texture))
			{
				Texture2D val = DeathRamp(texture);
				if (Object.op_Implicit((Object)(object)val))
				{
					material.SetTexture("_RemapTex", (Texture)(object)val);
				}
			}
		}

		private static Texture2D DeathRamp(Texture original)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_007b: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			if (deathRamps.TryGetValue(original, out var value))
			{
				return value;
			}
			Texture2D val = null;
			try
			{
				RenderTexture temporary = RenderTexture.GetTemporary(original.width, original.height, 0, (RenderTextureFormat)0);
				RenderTexture active = RenderTexture.active;
				Graphics.Blit(original, temporary);
				RenderTexture.active = temporary;
				val = new Texture2D(original.width, original.height, (TextureFormat)4, false)
				{
					name = ((Object)original).name + "_WhereToDieRed",
					wrapMode = original.wrapMode,
					filterMode = original.filterMode
				};
				val.ReadPixels(new Rect(0f, 0f, (float)original.width, (float)original.height), 0, 0);
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
				Color[] pixels = val.GetPixels();
				for (int i = 0; i < pixels.Length; i++)
				{
					pixels[i] = Tint(pixels[i]);
				}
				val.SetPixels(pixels);
				val.Apply();
				Object.DontDestroyOnLoad((Object)(object)val);
			}
			catch (Exception ex)
			{
				WhereToDiePlugin.Log.LogWarning((object)("Could not recolour the aurora ramp " + ((Object)original).name + ": " + ex.Message));
				val = null;
			}
			deathRamps[original] = val;
			return val;
		}
	}
	internal class AuroraFader : MonoBehaviour
	{
		private const float FadeDuration = 1.5f;

		private readonly List<(Material material, int property, Color color)> colors = new List<(Material, int, Color)>();

		private float fade;

		private float target = 1f;

		private void Awake()
		{
			//IL_0039: 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)
			ParticleSystemRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<ParticleSystemRenderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material[] materials = ((Renderer)componentsInChildren[i]).materials;
				foreach (Material val in materials)
				{
					if (!Object.op_Implicit((Object)(object)val))
					{
						continue;
					}
					Shader shader = val.shader;
					for (int k = 0; k < shader.GetPropertyCount(); k++)
					{
						if ((int)shader.GetPropertyType(k) == 0)
						{
							int propertyNameId = shader.GetPropertyNameId(k);
							colors.Add((val, propertyNameId, val.GetColor(propertyNameId)));
						}
					}
				}
			}
			Apply();
		}

		internal void FadeOutAndDestroy()
		{
			target = 0f;
			ParticleSystem[] componentsInChildren = ((Component)this).GetComponentsInChildren<ParticleSystem>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].Stop(false, (ParticleSystemStopBehavior)1);
			}
		}

		private void Update()
		{
			fade = Mathf.MoveTowards(fade, target, Time.deltaTime / 1.5f);
			Apply();
			if (target <= 0f && fade <= 0f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}

		private void Apply()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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)
			float num = Mathf.SmoothStep(0f, 1f, fade);
			foreach (var (val, num2, val2) in colors)
			{
				if (Object.op_Implicit((Object)(object)val))
				{
					val.SetColor(num2, val2 * num);
				}
			}
		}
	}
	internal class CustomZone : MonoBehaviour, IZone
	{
		internal float radius;

		internal float floorY = float.NegativeInfinity;

		internal Vector3 Center => ((Component)this).transform.position;

		public bool IsInBounds(Vector3 position)
		{
			//IL_0000: 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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = position - ((Component)this).transform.position;
			if (!float.IsNegativeInfinity(floorY))
			{
				if (position.y < floorY)
				{
					return false;
				}
				val.y = 0f;
			}
			return ((Vector3)(ref val)).sqrMagnitude <= radius * radius;
		}
	}
	internal static class ExtraZones
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_BeginEscapeSequence <0>__EscapeSequenceController_BeginEscapeSequence;

			public static hook_SpawnOutroPortal <1>__VoidRaidGauntletController_SpawnOutroPortal;
		}

		private const string MoonScene = "moon2";

		private const string PlanetariumScene = "voidraid";

		private const string MessageFormat = "<color=#7BE35A><b>{0}</b></color>";

		private const float PlanetariumRadius = 150f;

		private const float RoofTolerance = 3f;

		private static FieldInfo useExplicitSceneField;

		private static FieldInfo explicitSceneField;

		private static FieldInfo currentDonutField;

		internal static void Init()
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			useExplicitSceneField = typeof(CursedBookSacrificeZone).GetField("useExplicitSceneInstead", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			explicitSceneField = typeof(CursedBookSacrificeZone).GetField("explicitScene", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			currentDonutField = typeof(VoidRaidGauntletController).GetField("currentDonut", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (useExplicitSceneField == null || explicitSceneField == null)
			{
				WhereToDiePlugin.Log.LogError((object)"CursedBookSacrificeZone fields not found; the new places to use Reincarnation are disabled.");
			}
			object obj = <>O.<0>__EscapeSequenceController_BeginEscapeSequence;
			if (obj == null)
			{
				hook_BeginEscapeSequence val = EscapeSequenceController_BeginEscapeSequence;
				<>O.<0>__EscapeSequenceController_BeginEscapeSequence = val;
				obj = (object)val;
			}
			EscapeSequenceController.BeginEscapeSequence += (hook_BeginEscapeSequence)obj;
			object obj2 = <>O.<1>__VoidRaidGauntletController_SpawnOutroPortal;
			if (obj2 == null)
			{
				hook_SpawnOutroPortal val2 = VoidRaidGauntletController_SpawnOutroPortal;
				<>O.<1>__VoidRaidGauntletController_SpawnOutroPortal = val2;
				obj2 = (object)val2;
			}
			VoidRaidGauntletController.SpawnOutroPortal += (hook_SpawnOutroPortal)obj2;
		}

		private static bool CanCreate(string scene, bool enabled)
		{
			if (enabled && NetworkServer.active && Object.op_Implicit((Object)(object)Run.instance) && PageFixes.CurrentSceneName() == scene && !PageFixes.HasEnteredLucidity() && useExplicitSceneField != null)
			{
				return explicitSceneField != null;
			}
			return false;
		}

		private static void EscapeSequenceController_BeginEscapeSequence(orig_BeginEscapeSequence orig, EscapeSequenceController self)
		{
			//IL_0053: 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_00cb: 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_00e9: 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)
			//IL_00f8: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(self);
			if (!CanCreate("moon2", WhereToDiePlugin.RocketshipRoof.Value))
			{
				return;
			}
			GameObject ship = FindSceneObject("RescueshipMoon");
			if (!Object.op_Implicit((Object)(object)ship))
			{
				WhereToDiePlugin.Log.LogWarning((object)"Rocketship not found on the Moon; no Reincarnation zone on its roof.");
				return;
			}
			Bounds val = default(Bounds);
			bool flag = false;
			Renderer[] componentsInChildren = ship.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (!(val2 is ParticleSystemRenderer))
				{
					if (flag)
					{
						((Bounds)(ref val)).Encapsulate(val2.bounds);
						continue;
					}
					val = val2.bounds;
					flag = true;
				}
			}
			if (!flag)
			{
				WhereToDiePlugin.Log.LogWarning((object)"Rocketship has no renderers; no Reincarnation zone on its roof.");
				return;
			}
			float y = ((Bounds)(ref val)).max.y;
			Vector3 val3 = new Vector3(((Bounds)(ref val)).center.x, ((Bounds)(ref val)).max.y + 20f, ((Bounds)(ref val)).center.z);
			Vector3 down = Vector3.down;
			float num = ((Bounds)(ref val)).size.y + 40f;
			LayerIndex world = LayerIndex.world;
			RaycastHit val4 = (from h in Physics.RaycastAll(val3, down, num, LayerMask.op_Implicit(((LayerIndex)(ref world)).mask), (QueryTriggerInteraction)1)
				where ((Component)((RaycastHit)(ref h)).collider).transform.IsChildOf(ship.transform)
				orderby ((RaycastHit)(ref h)).distance
				select h).FirstOrDefault();
			if (Object.op_Implicit((Object)(object)((RaycastHit)(ref val4)).collider))
			{
				y = ((RaycastHit)(ref val4)).point.y;
				WhereToDiePlugin.Log.LogDebug((object)$"Rocketship roof: {((Object)((RaycastHit)(ref val4)).collider).name} at {((RaycastHit)(ref val4)).point}.");
			}
			else
			{
				WhereToDiePlugin.Log.LogWarning((object)"Rocketship has no world collider under its centre; using its bounds instead.");
			}
			float radius = Mathf.Max(((Bounds)(ref val)).extents.x, ((Bounds)(ref val)).extents.z) * 0.6f;
			CreateZone("RocketshipRoof", new Vector3(((Bounds)(ref val)).center.x, y, ((Bounds)(ref val)).center.z), radius, y - 3f, "Found a way to escape the Moon");
		}

		private static void VoidRaidGauntletController_SpawnOutroPortal(orig_SpawnOutroPortal orig, VoidRaidGauntletController self)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			orig.Invoke(self);
			if (!CanCreate("voidraid", WhereToDiePlugin.PlanetariumFinale.Value))
			{
				return;
			}
			object? obj = currentDonutField?.GetValue(self);
			DonutInfo val = (DonutInfo)((obj is DonutInfo) ? obj : null);
			if (val == null || !Object.op_Implicit((Object)(object)val.root))
			{
				WhereToDiePlugin.Log.LogWarning((object)"Planetarium final arena not found; no Reincarnation zone there.");
				return;
			}
			Bounds val2 = default(Bounds);
			bool flag = false;
			Collider[] componentsInChildren = val.root.GetComponentsInChildren<Collider>(true);
			foreach (Collider val3 in componentsInChildren)
			{
				if (val3.isTrigger)
				{
					continue;
				}
				LayerIndex world = LayerIndex.world;
				if ((LayerMask.op_Implicit(((LayerIndex)(ref world)).mask) & (1 << ((Component)val3).gameObject.layer)) != 0)
				{
					if (flag)
					{
						((Bounds)(ref val2)).Encapsulate(val3.bounds);
						continue;
					}
					val2 = val3.bounds;
					flag = true;
				}
			}
			if (!flag)
			{
				Transform val4 = (Object.op_Implicit((Object)(object)val.crabPosition) ? val.crabPosition : val.returnPoint);
				((Bounds)(ref val2))..ctor(Object.op_Implicit((Object)(object)val4) ? val4.position : val.root.transform.position, Vector3.one * 150f * 2f);
				WhereToDiePlugin.Log.LogWarning((object)"Planetarium final arena has no world colliders; using a fixed radius.");
			}
			float radius = Mathf.Max(((Bounds)(ref val2)).extents.x, ((Bounds)(ref val2)).extents.z);
			CreateZone("PlanetariumFinale", ((Bounds)(ref val2)).center, radius, float.NegativeInfinity, "Found peace in the Void", tube: true);
		}

		private static void CreateZone(string name, Vector3 position, float radius, float floorY, string message, bool tube = false)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			SceneDef val = SceneCatalog.FindSceneDef("champrush");
			if (!Object.op_Implicit((Object)(object)val) || (Object.op_Implicit((Object)(object)val.requiredExpansion) && !Run.instance.IsExpansionEnabled(val.requiredExpansion)))
			{
				WhereToDiePlugin.Log.LogWarning((object)"The Soulbound Threshold isn't available in this run.");
				return;
			}
			GameObject val2 = new GameObject("WhereToDie_" + name);
			val2.SetActive(false);
			val2.transform.position = position;
			CustomZone customZone = val2.AddComponent<CustomZone>();
			customZone.radius = radius;
			customZone.floorY = (tube ? (-1000000f) : floorY);
			CursedBookSacrificeZone val3 = val2.AddComponent<CursedBookSacrificeZone>();
			val3.behaviour = (Behaviour)0;
			useExplicitSceneField.SetValue(val3, true);
			explicitSceneField.SetValue(val3, val);
			val3.OnTriggered = (UnityEvent)(((object)val3.OnTriggered) ?? ((object)new UnityEvent()));
			string text = $"<color=#7BE35A><b>{message}</b></color>";
			val3.OnTriggered.AddListener((UnityAction)delegate
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Expected O, but got Unknown
				Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
				{
					baseToken = text
				});
				FinalePath.Begin();
			});
			val2.SetActive(true);
			CursedBookSacrificeZone.instanceList.Remove(val3);
			CursedBookSacrificeZone.instanceList.Insert(0, val3);
			WhereToDiePlugin.Log.LogInfo((object)$"Added Reincarnation zone '{name}' at {position} (radius {radius:0.#}).");
		}

		private static GameObject FindSceneObject(string name)
		{
			GameObject val = GameObject.Find(name);
			if (Object.op_Implicit((Object)(object)val))
			{
				return val;
			}
			Transform[] array = Object.FindObjectsOfType<Transform>();
			foreach (Transform val2 in array)
			{
				if (((Object)val2).name == name)
				{
					return ((Component)val2).gameObject;
				}
			}
			return null;
		}
	}
	internal static class FinalePath
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_AttemptSpawnPortalServer <0>__PortalSpawner_AttemptSpawnPortalServer;

			public static hook_OnEnter <1>__EncounterFinished_OnEnter;

			public static hook_AdvanceStage <2>__Run_AdvanceStage;

			public static hook_DoFinalAction <3>__EndingGame_DoFinalAction;

			public static Action<Stage> <4>__OnServerStageBegin;
		}

		internal const string Flag = "WhereToDie_FinalePath";

		internal const string ObliterationScene = "mysteryspace";

		private const string ObliterationPortalAddress = "RoR2/Base/PortalMS/iscMSPortal.asset";

		private const string ObliterationPortalToken = "PORTAL_MS_OPEN";

		private static InteractableSpawnCard obliterationPortal;

		private static FieldInfo portalSpawnCardField;

		private static FieldInfo spawnMessageTokenField;

		internal static void Init()
		{
			//IL_0005: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//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_00e2: Expected O, but got Unknown
			AsyncOperationHandle<InteractableSpawnCard> val = Addressables.LoadAssetAsync<InteractableSpawnCard>((object)"RoR2/Base/PortalMS/iscMSPortal.asset");
			val.Completed += delegate(AsyncOperationHandle<InteractableSpawnCard> handle)
			{
				obliterationPortal = handle.Result;
				if (!Object.op_Implicit((Object)(object)obliterationPortal))
				{
					WhereToDiePlugin.Log.LogError((object)"RoR2/Base/PortalMS/iscMSPortal.asset not found; the finale path can't offer Obliteration.");
				}
			};
			portalSpawnCardField = typeof(PortalSpawner).GetField("portalSpawnCard", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			spawnMessageTokenField = typeof(PortalSpawner).GetField("spawnMessageToken", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			object obj = <>O.<0>__PortalSpawner_AttemptSpawnPortalServer;
			if (obj == null)
			{
				hook_AttemptSpawnPortalServer val2 = PortalSpawner_AttemptSpawnPortalServer;
				<>O.<0>__PortalSpawner_AttemptSpawnPortalServer = val2;
				obj = (object)val2;
			}
			PortalSpawner.AttemptSpawnPortalServer += (hook_AttemptSpawnPortalServer)obj;
			object obj2 = <>O.<1>__EncounterFinished_OnEnter;
			if (obj2 == null)
			{
				hook_OnEnter val3 = EncounterFinished_OnEnter;
				<>O.<1>__EncounterFinished_OnEnter = val3;
				obj2 = (object)val3;
			}
			EncounterFinished.OnEnter += (hook_OnEnter)obj2;
			object obj3 = <>O.<2>__Run_AdvanceStage;
			if (obj3 == null)
			{
				hook_AdvanceStage val4 = Run_AdvanceStage;
				<>O.<2>__Run_AdvanceStage = val4;
				obj3 = (object)val4;
			}
			Run.AdvanceStage += (hook_AdvanceStage)obj3;
			object obj4 = <>O.<3>__EndingGame_DoFinalAction;
			if (obj4 == null)
			{
				hook_DoFinalAction val5 = EndingGame_DoFinalAction;
				<>O.<3>__EndingGame_DoFinalAction = val5;
				obj4 = (object)val5;
			}
			EndingGame.DoFinalAction += (hook_DoFinalAction)obj4;
			Stage.onServerStageBegin += OnServerStageBegin;
		}

		internal static bool IsActive()
		{
			if (WhereToDiePlugin.FinaleToObliteration.Value && NetworkServer.active && Object.op_Implicit((Object)(object)Run.instance))
			{
				return Run.instance.GetEventFlag("WhereToDie_FinalePath");
			}
			return false;
		}

		internal static void Begin()
		{
			if (Object.op_Implicit((Object)(object)Run.instance) && NetworkServer.active)
			{
				Run.instance.SetEventFlag("WhereToDie_FinalePath");
			}
		}

		private static bool PortalSpawner_AttemptSpawnPortalServer(orig_AttemptSpawnPortalServer orig, PortalSpawner self)
		{
			if (!IsActive() || !Object.op_Implicit((Object)(object)obliterationPortal) || PageFixes.CurrentSceneName() != "champrush" || portalSpawnCardField == null || spawnMessageTokenField == null)
			{
				return orig.Invoke(self);
			}
			object value = portalSpawnCardField.GetValue(self);
			object value2 = spawnMessageTokenField.GetValue(self);
			portalSpawnCardField.SetValue(self, obliterationPortal);
			spawnMessageTokenField.SetValue(self, "PORTAL_MS_OPEN");
			try
			{
				bool flag = orig.Invoke(self);
				WhereToDiePlugin.Log.LogInfo((object)$"Finale path: Obliteration portal instead of the way back (spawned={flag}).");
				return flag;
			}
			finally
			{
				portalSpawnCardField.SetValue(self, value);
				spawnMessageTokenField.SetValue(self, value2);
			}
		}

		private static void EncounterFinished_OnEnter(orig_OnEnter orig, EncounterFinished self)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			if (IsActive() && Object.op_Implicit((Object)(object)obliterationPortal))
			{
				self.teleporterCard = obliterationPortal;
				Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
				{
					baseToken = "PORTAL_MS_OPEN"
				});
				WhereToDiePlugin.Log.LogInfo((object)"Finale path: Obliteration portal instead of the final teleporter.");
			}
			orig.Invoke(self);
		}

		private static void Run_AdvanceStage(orig_AdvanceStage orig, Run self, SceneDef nextScene)
		{
			if (IsActive())
			{
				string text = PageFixes.CurrentSceneName();
				string text2 = (Object.op_Implicit((Object)(object)nextScene) ? nextScene.cachedName : "");
				switch (text)
				{
				case "mysteryspace":
					WhereToDiePlugin.Log.LogInfo((object)("Finale path: blocked leaving Obliteration for '" + text2 + "'."));
					return;
				case "champrush":
				case "ultima":
					if (text2 != "ultima" && text2 != "mysteryspace")
					{
						SceneDef val = SceneCatalog.FindSceneDef("mysteryspace");
						if (Object.op_Implicit((Object)(object)val))
						{
							WhereToDiePlugin.Log.LogInfo((object)("Finale path: '" + text2 + "' replaced with Obliteration."));
							nextScene = val;
						}
					}
					break;
				}
			}
			orig.Invoke(self, nextScene);
		}

		private static void EndingGame_DoFinalAction(orig_DoFinalAction orig, EndingGame self)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			if (!IsActive())
			{
				orig.Invoke(self);
				return;
			}
			WhereToDiePlugin.Log.LogInfo((object)"Finale path: obliterated; Beads of Fealty don't lead to A Moment, Whole.");
			Run.instance.BeginGameOver(GameEndings.ObliterationEnding);
			((EntityState)self).outer.SetNextState((EntityState)new Idle());
		}

		private static void OnServerStageBegin(Stage stage)
		{
			if (!IsActive() || PageFixes.CurrentSceneName() != "mysteryspace")
			{
				return;
			}
			foreach (CursedBookSacrificeZone instance in CursedBookSacrificeZone.instanceList)
			{
				if (Object.op_Implicit((Object)(object)instance))
				{
					instance.SetDisabled(true);
				}
			}
		}
	}
	internal static class PageFixes
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_AttemptGrant <0>__KeyItemDef_AttemptGrant;

			public static Action<Stage> <1>__OnServerStageBegin;
		}

		internal const string ThresholdScene = "champrush";

		internal const string LucidityScene = "ultima";

		internal const string LucidityEnteredFlag = "WhereToDie_UltimaEntered";

		private const string LucidityCompletedFlag = "ULTIMA_COMPLETED";

		private const string ReaperDefeatedFlag = "ReaperBossDefeated";

		internal static void Init()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			object obj = <>O.<0>__KeyItemDef_AttemptGrant;
			if (obj == null)
			{
				hook_AttemptGrant val = KeyItemDef_AttemptGrant;
				<>O.<0>__KeyItemDef_AttemptGrant = val;
				obj = (object)val;
			}
			KeyItemDef.AttemptGrant += (hook_AttemptGrant)obj;
			Stage.onServerStageBegin += OnServerStageBegin;
		}

		internal static bool HasEnteredLucidity()
		{
			Run instance = Run.instance;
			if (Object.op_Implicit((Object)(object)instance))
			{
				if (!instance.GetEventFlag("WhereToDie_UltimaEntered"))
				{
					return instance.GetEventFlag("ULTIMA_COMPLETED");
				}
				return true;
			}
			return false;
		}

		internal static string CurrentSceneName()
		{
			SceneDef sceneDefForCurrentScene = SceneCatalog.GetSceneDefForCurrentScene();
			if (!Object.op_Implicit((Object)(object)sceneDefForCurrentScene))
			{
				return "";
			}
			return sceneDefForCurrentScene.cachedName;
		}

		private static void KeyItemDef_AttemptGrant(orig_AttemptGrant orig, ref GrantContext context)
		{
			//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_005e: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			Inventory val = (Object.op_Implicit((Object)(object)context.body) ? context.body.inventory : null);
			KeyItemIndex val2 = (KeyItemIndex)((!Object.op_Implicit((Object)(object)val)) ? (-1) : ((int)val.keyItemIndex));
			orig.Invoke(ref context);
			KeyItemDef cursedBook = KeyItems.CursedBook;
			if (NetworkServer.active && WhereToDiePlugin.GivePageWithBook.Value && Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)cursedBook) && val2 != cursedBook.keyItemIndex && val.keyItemIndex == cursedBook.keyItemIndex)
			{
				CharacterMaster master = context.body.master;
				if (Object.op_Implicit((Object)(object)master) && Object.op_Implicit((Object)(object)master.playerCharacterMasterController) && val.GetItemCountEffective(Items.PageDie) <= 0 && val.GetItemCountEffective(Items.PageDieConsumed) <= 0)
				{
					val.GiveItemPermanent(Items.PageDie, 1);
					WhereToDiePlugin.Log.LogInfo((object)("Gave the Page of Reincarnation to " + master.playerCharacterMasterController.GetDisplayName() + " with the N'tormat."));
				}
			}
		}

		private static void OnServerStageBegin(Stage stage)
		{
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)Run.instance))
			{
				return;
			}
			string text = CurrentSceneName();
			if (text == "ultima")
			{
				Run.instance.SetEventFlag("WhereToDie_UltimaEntered");
			}
			else if (text == "champrush")
			{
				if (WhereToDiePlugin.RefreshPageInThreshold.Value)
				{
					RefreshReincarnation();
				}
			}
			else if (WhereToDiePlugin.ThresholdReentry.Value)
			{
				AllowThresholdReentry();
			}
		}

		private static void RefreshReincarnation()
		{
			//IL_0094: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			CursedBookSpellDef die = CursedBookSpells.Die;
			if (!Object.op_Implicit((Object)(object)die))
			{
				return;
			}
			TryTransformResult val4 = default(TryTransformResult);
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				Inventory val = ((Object.op_Implicit((Object)(object)instance) && Object.op_Implicit((Object)(object)instance.master)) ? instance.master.inventory : null);
				if (!Object.op_Implicit((Object)(object)val))
				{
					continue;
				}
				if (Object.op_Implicit((Object)(object)die.cooldownItemDef))
				{
					int itemCountPermanent = val.GetItemCountPermanent(die.cooldownItemDef);
					if (itemCountPermanent > 0)
					{
						val.RemoveItemPermanent(die.cooldownItemDef, itemCountPermanent);
					}
				}
				if (val.GetItemCountEffective(die.consumedItemDef) > 0)
				{
					ItemTransformation val2 = default(ItemTransformation);
					((ItemTransformation)(ref val2)).originalItemIndex = die.consumedItemDef.itemIndex;
					((ItemTransformation)(ref val2)).newItemIndex = die.itemDef.itemIndex;
					((ItemTransformation)(ref val2)).maxToTransform = int.MaxValue;
					val2.transformationType = (ItemTransformationTypeIndex)0;
					ItemTransformation val3 = val2;
					if (((ItemTransformation)(ref val3)).TryTransform(val, ref val4))
					{
						WhereToDiePlugin.Log.LogInfo((object)("Recharged the Page of Reincarnation of " + instance.GetDisplayName() + " in the Soulbound Threshold."));
					}
				}
			}
		}

		private static void AllowThresholdReentry()
		{
			Run instance = Run.instance;
			if (HasEnteredLucidity())
			{
				return;
			}
			DLC4ProgressionController instance2 = DLC4ProgressionController.instance;
			if (!instance.GetEventFlag("ReaperBossDefeated") && (!Object.op_Implicit((Object)(object)instance2) || !instance2.ReaperBossDefeated))
			{
				return;
			}
			instance.ResetEventFlag("ReaperBossDefeated");
			if (Object.op_Implicit((Object)(object)instance2))
			{
				instance2.NetworkreaperBossDefeated = false;
				DLC4CatastropheProvider catastropheProvider = instance2.catastropheProvider;
				if (Object.op_Implicit((Object)(object)catastropheProvider))
				{
					catastropheProvider.NetworkhasSpawnedMajorCatastrophe = false;
					catastropheProvider.NetworkshouldDoMajorCatastrophe = false;
				}
			}
			WhereToDiePlugin.Log.LogInfo((object)"Terminal Lucidity not entered yet: the Soulbound Threshold can be entered again.");
		}

		internal static string StatusText()
		{
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)Run.instance))
			{
				return "";
			}
			DLC4ProgressionController instance = DLC4ProgressionController.instance;
			return $"scene={CurrentSceneName()} lucidityEntered={HasEnteredLucidity()} " + string.Format("reaperDefeated={0}", Object.op_Implicit((Object)(object)instance) ? instance.ReaperBossDefeated : Run.instance.GetEventFlag("ReaperBossDefeated"));
		}
	}
	internal static class PageIconHighlighter
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_Update <0>__CursedBookSpellSlotIcon_Update;
		}

		private static FieldInfo spellSlotField;

		private static FieldInfo ownerField;

		private static readonly Dictionary<Sprite, Sprite> greyscaleSprites = new Dictionary<Sprite, Sprite>();

		internal static void Init()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			spellSlotField = typeof(CursedBookSpellSlotIcon).GetField("spellSlot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			ownerField = typeof(SpellSlot).GetField("owner", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (spellSlotField == null || ownerField == null)
			{
				WhereToDiePlugin.Log.LogError((object)"CursedBookSpellSlotIcon fields not found; the page icon highlight is disabled.");
				return;
			}
			object obj = <>O.<0>__CursedBookSpellSlotIcon_Update;
			if (obj == null)
			{
				hook_Update val = CursedBookSpellSlotIcon_Update;
				<>O.<0>__CursedBookSpellSlotIcon_Update = val;
				obj = (object)val;
			}
			CursedBookSpellSlotIcon.Update += (hook_Update)obj;
		}

		private static void CursedBookSpellSlotIcon_Update(orig_Update orig, CursedBookSpellSlotIcon self)
		{
			orig.Invoke(self);
			bool? state = (WhereToDiePlugin.PageIconHighlight.Value ? State(self) : ((bool?)null));
			PageIconGradient pageIconGradient = ((Component)self).GetComponent<PageIconGradient>();
			if (!Object.op_Implicit((Object)(object)pageIconGradient))
			{
				if (!state.HasValue || !Object.op_Implicit((Object)(object)((Component)self).GetComponent<Image>()))
				{
					return;
				}
				pageIconGradient = ((Component)self).gameObject.AddComponent<PageIconGradient>();
			}
			pageIconGradient.SetState(state);
			Image component = ((Component)self).GetComponent<Image>();
			if (state.HasValue && Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.sprite))
			{
				component.sprite = GreyscaleSprite(component.sprite);
			}
		}

		private static Sprite GreyscaleSprite(Sprite source)
		{
			if (greyscaleSprites.TryGetValue(source, out var value))
			{
				if (!Object.op_Implicit((Object)(object)value))
				{
					return source;
				}
				return value;
			}
			if (greyscaleSprites.ContainsValue(source))
			{
				return source;
			}
			Sprite val = null;
			try
			{
				val = MakeGreyscale(source);
			}
			catch (Exception ex)
			{
				WhereToDiePlugin.Log.LogWarning((object)("Could not recolour " + ((Object)source).name + ": " + ex.Message));
			}
			greyscaleSprites[source] = val;
			if (!Object.op_Implicit((Object)(object)val))
			{
				return source;
			}
			return val;
		}

		private static Sprite MakeGreyscale(Sprite source)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			Texture2D texture = source.texture;
			Rect textureRect = source.textureRect;
			int num = Mathf.RoundToInt(((Rect)(ref textureRect)).width);
			int num2 = Mathf.RoundToInt(((Rect)(ref textureRect)).height);
			RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0);
			RenderTexture active = RenderTexture.active;
			Graphics.Blit((Texture)(object)texture, temporary);
			RenderTexture.active = temporary;
			Texture2D val = new Texture2D(num, num2, (TextureFormat)4, false)
			{
				name = ((Object)source).name + "_WhereToDie"
			};
			val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
			RenderTexture.active = active;
			RenderTexture.ReleaseTemporary(temporary);
			Color[] pixels = val.GetPixels();
			float num3 = 0.001f;
			Color[] array = pixels;
			for (int i = 0; i < array.Length; i++)
			{
				Color val2 = array[i];
				if (val2.a > 0.1f)
				{
					num3 = Mathf.Max(num3, ((Color)(ref val2)).maxColorComponent);
				}
			}
			for (int j = 0; j < pixels.Length; j++)
			{
				float num4 = Mathf.Clamp01(((Color)(ref pixels[j])).maxColorComponent / num3);
				pixels[j] = new Color(num4, num4, num4, pixels[j].a);
			}
			val.SetPixels(pixels);
			val.Apply();
			Object.DontDestroyOnLoad((Object)(object)val);
			float x = source.pivot.x;
			Rect rect = source.rect;
			float num5 = x / ((Rect)(ref rect)).width;
			float y = source.pivot.y;
			rect = source.rect;
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(num5, y / ((Rect)(ref rect)).height);
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num2), val3, source.pixelsPerUnit);
			((Object)obj).name = ((Object)val).name;
			Object.DontDestroyOnLoad((Object)(object)obj);
			return obj;
		}

		private static bool? State(CursedBookSpellSlotIcon icon)
		{
			//IL_0023: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			object? value = spellSlotField.GetValue(icon);
			SpellSlot val = (SpellSlot)((value is SpellSlot) ? value : null);
			CursedBookSpellDef die = CursedBookSpells.Die;
			if (val == null || !Object.op_Implicit((Object)(object)die) || val.spellIndex != die.spellIndex || val.isConsumed)
			{
				return null;
			}
			object? value2 = ownerField.GetValue(val);
			CursedBookBodyBehavior val2 = (CursedBookBodyBehavior)((value2 is CursedBookBodyBehavior) ? value2 : null);
			CharacterBody val3 = (Object.op_Implicit((Object)(object)val2) ? ((BaseKeyItemBodyBehavior)val2).body : null);
			if (!Object.op_Implicit((Object)(object)val3) || !val3.HasBuff(Buffs.CursedBookReadyForSacrifice))
			{
				return null;
			}
			return ZoneTracker.DiesAt(val3.corePosition) ?? true;
		}
	}
	internal class PageIconGradient : BaseMeshEffect
	{
		internal static readonly Color Green = new Color(0.35f, 1f, 0.3f, 1f);

		internal static readonly Color Yellow = new Color(1f, 0.9f, 0.2f, 1f);

		internal static readonly Color Red = new Color(1f, 0.18f, 0.12f, 1f);

		internal bool? Dies { get; private set; }

		internal void SetState(bool? dies)
		{
			if (dies != Dies)
			{
				Dies = dies;
				if (Object.op_Implicit((Object)(object)((BaseMeshEffect)this).graphic))
				{
					((BaseMeshEffect)this).graphic.SetVerticesDirty();
				}
			}
		}

		public override void ModifyMesh(VertexHelper vh)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: 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_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			if (!((UIBehaviour)this).IsActive() || !Dies.HasValue || vh.currentVertCount == 0)
			{
				return;
			}
			Color val = (Dies.Value ? Red : Yellow);
			List<UIVertex> list = new List<UIVertex>();
			vh.GetUIVertexStream(list);
			float num = float.MaxValue;
			float num2 = float.MinValue;
			foreach (UIVertex item in list)
			{
				num = Mathf.Min(num, item.position.y);
				num2 = Mathf.Max(num2, item.position.y);
			}
			float num3 = Mathf.Max(num2 - num, 0.001f);
			for (int i = 0; i < list.Count; i++)
			{
				UIVertex val2 = list[i];
				Color val3 = Color.Lerp(Green, val, (val2.position.y - num) / num3);
				val3.a = (float)(int)val2.color.a / 255f;
				val2.color = Color32.op_Implicit(val3);
				list[i] = val2;
			}
			vh.Clear();
			vh.AddUIVertexTriangleStream(list);
		}
	}
	internal static class RiskOfOptionsCompat
	{
		internal const string PluginGUID = "com.rune580.riskofoptions";

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		internal static void Init(string pluginDirectory)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			ModSettingsManager.SetModDescription("Quality of life for the Page of Reincarnation (N'tormat). Shows where the page works and whether the ritual kills you, gives the page with the N'tormat, recharges it in the Soulbound Threshold and adds new places to use it. Options marked \"Host only\" only matter when you host.", "com.elevated.WhereToDie", "Where To Die");
			Sprite val = LoadIcon(Path.Combine(pluginDirectory, "icon.png"));
			if (Object.op_Implicit((Object)(object)val))
			{
				ModSettingsManager.SetModIcon(val, "com.elevated.WhereToDie", "Where To Die");
			}
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(WhereToDiePlugin.PageIconHighlight), "com.elevated.WhereToDie", "Where To Die");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(WhereToDiePlugin.HallowedAurora), "com.elevated.WhereToDie", "Where To Die");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(WhereToDiePlugin.GivePageWithBook), "com.elevated.WhereToDie", "Where To Die");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(WhereToDiePlugin.RefreshPageInThreshold), "com.elevated.WhereToDie", "Where To Die");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(WhereToDiePlugin.RocketshipRoof), "com.elevated.WhereToDie", "Where To Die");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(WhereToDiePlugin.PlanetariumFinale), "com.elevated.WhereToDie", "Where To Die");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(WhereToDiePlugin.ThresholdReentry), "com.elevated.WhereToDie", "Where To Die");
			ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(WhereToDiePlugin.FinaleToObliteration), "com.elevated.WhereToDie", "Where To Die");
		}

		private static Sprite LoadIcon(string path)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_003b: 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)
			if (!File.Exists(path))
			{
				return null;
			}
			Texture2D val = new Texture2D(2, 2);
			if (!ImageConversion.LoadImage(val, File.ReadAllBytes(path)))
			{
				return null;
			}
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
		}
	}
	[BepInPlugin("com.elevated.WhereToDie", "WhereToDie", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class WhereToDiePlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.elevated.WhereToDie";

		public const string PluginName = "WhereToDie";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> PageIconHighlight;

		internal static ConfigEntry<bool> HallowedAurora;

		internal static ConfigEntry<bool> GivePageWithBook;

		internal static ConfigEntry<bool> RefreshPageInThreshold;

		internal static ConfigEntry<bool> RocketshipRoof;

		internal static ConfigEntry<bool> PlanetariumFinale;

		internal static ConfigEntry<bool> ThresholdReentry;

		internal static ConfigEntry<bool> FinaleToObliteration;

		public void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			PageIconHighlight = ((BaseUnityPlugin)this).Config.Bind<bool>("Die or Not", "Page icon highlight", true, "Highlights the Reincarnation page above the N'tormat while you stand where it works: green-yellow if you survive the ritual, green-red if it kills you.");
			HallowedAurora = ((BaseUnityPlugin)this).Config.Bind<bool>("Die or Not", "Hallowed aurora", true, "Shows a hallowed aurora above every place where Reincarnation works while you hold an unused page: yellow if you survive the ritual, red if it kills you. The first 30 seconds of a normal stage light up the whole stage with a sparser aurora. Needs the host to have the mod.");
			GivePageWithBook = ((BaseUnityPlugin)this).Config.Bind<bool>("Quality", "Give Reincarnation with the N’tormat", true, "Host only. Picking up the N'tormat also gives the Page of Reincarnation, if you don't have it yet.");
			RefreshPageInThreshold = ((BaseUnityPlugin)this).Config.Bind<bool>("Quality", "Refresh Reincarnation in the Soulbound Threshold", true, "Host only. Arriving in the Soulbound Threshold recharges a used Page of Reincarnation, so one page is enough to continue to Terminal Lucidity.");
			RocketshipRoof = ((BaseUnityPlugin)this).Config.Bind<bool>("Space and Time", "Rocketship roof", true, "Host only. After Mithrix is defeated, dying by Reincarnation on top of the rocketship on the Moon takes you to the Soulbound Threshold.");
			PlanetariumFinale = ((BaseUnityPlugin)this).Config.Bind<bool>("Space and Time", "Planetarium final arena", true, "Host only. After Voidling is defeated, dying by Reincarnation in its final arena takes you to the Soulbound Threshold.");
			ThresholdReentry = ((BaseUnityPlugin)this).Config.Bind<bool>("Space and Time", "Re-enter the Soulbound Threshold", true, "Host only. If you defeated the Anima Harvester but never entered Terminal Lucidity, the Shrine of Descent and the soul-binding trial come back so you can enter the Soulbound Threshold again.");
			FinaleToObliteration = ((BaseUnityPlugin)this).Config.Bind<bool>("Space and Time", "No way back after the finale", true, "Host only. After leaving the Moon or the Planetarium through Reincarnation, the Soulbound Threshold and Terminal Lucidity offer a portal to Obliteration instead of their way back to the run, and Obliteration has no way back either.");
			ZoneNetwork.Init();
			ZoneTracker.Init();
			ExtraZones.Init();
			FinalePath.Init();
			PageFixes.Init();
			AuroraRenderer.Init();
			PageIconHighlighter.Init();
			if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"))
			{
				RiskOfOptionsCompat.Init(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location));
			}
		}
	}
	internal static class ZoneNetwork
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static NetworkUserGenericDelegate <0>__OnPostNetworkUserStart;

			public static Action <1>__ResetClientState;
		}

		internal const short MarkersMessageType = 22340;

		private const byte ProtocolVersion = 1;

		private const byte FlagDies = 1;

		private const byte FlagStageWide = 2;

		private const byte FlagTube = 4;

		private static readonly HashSet<NetworkConnection> moddedConnections = new HashSet<NetworkConnection>();

		internal static bool HostHasMod { get; private set; }

		internal static void Init()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			object obj = <>O.<0>__OnPostNetworkUserStart;
			if (obj == null)
			{
				NetworkUserGenericDelegate val = OnPostNetworkUserStart;
				<>O.<0>__OnPostNetworkUserStart = val;
				obj = (object)val;
			}
			NetworkUser.onPostNetworkUserStart += (NetworkUserGenericDelegate)obj;
			NetworkManagerSystem.onStartClientGlobal += delegate
			{
				ResetClientState();
			};
			NetworkManagerSystem.onStopClientGlobal += ResetClientState;
			NetworkManagerSystem.onStartServerGlobal += moddedConnections.Clear;
			NetworkManagerSystem.onStopServerGlobal += moddedConnections.Clear;
			NetworkManagerSystem.onServerDisconnectGlobal += delegate(NetworkConnection conn)
			{
				moddedConnections.Remove(conn);
			};
		}

		private static void ResetClientState()
		{
			HostHasMod = false;
			if (!NetworkServer.active)
			{
				ZoneTracker.SetMarkers(new List<ZoneMarker>());
			}
		}

		private static void OnPostNetworkUserStart(NetworkUser networkUser)
		{
			if (!NetworkServer.active && Object.op_Implicit((Object)(object)networkUser) && ((NetworkBehaviour)networkUser).isLocalPlayer)
			{
				Console.instance.SubmitCmd(networkUser, "wheretodie_hello", false);
			}
		}

		internal static void BroadcastMarkers()
		{
			if (!NetworkServer.active)
			{
				return;
			}
			moddedConnections.RemoveWhere((NetworkConnection conn) => conn == null || !conn.isConnected);
			foreach (NetworkConnection moddedConnection in moddedConnections)
			{
				SendMarkers(moddedConnection);
			}
		}

		private static void SendMarkers(NetworkConnection conn)
		{
			conn.SendWriter(WriteMarkers(ZoneTracker.Markers), QosChannelIndex.defaultReliable.intVal);
		}

		internal static NetworkWriter WriteMarkers(List<ZoneMarker> markers)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			NetworkWriter val = new NetworkWriter();
			val.StartMessage((short)22340);
			val.Write((byte)1);
			val.Write((byte)Mathf.Min(markers.Count, 255));
			for (int i = 0; i < markers.Count && i < 255; i++)
			{
				ZoneMarker zoneMarker = markers[i];
				byte b = 0;
				if (zoneMarker.Dies)
				{
					b |= 1;
				}
				if (zoneMarker.StageWide)
				{
					b |= 2;
				}
				if (zoneMarker.Tube)
				{
					b |= 4;
				}
				val.Write(zoneMarker.Position);
				val.Write(zoneMarker.Radius);
				val.Write(b);
			}
			val.FinishMessage();
			return val;
		}

		internal static List<ZoneMarker> ReadMarkers(NetworkReader reader)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			byte b = reader.ReadByte();
			if (b != 1)
			{
				WhereToDiePlugin.Log.LogWarning((object)$"Host uses a different WhereToDie protocol ({b}, expected {(byte)1}); update the mod.");
				return null;
			}
			int num = reader.ReadByte();
			List<ZoneMarker> list = new List<ZoneMarker>(num);
			for (int i = 0; i < num; i++)
			{
				Vector3 position = reader.ReadVector3();
				float radius = reader.ReadSingle();
				byte b2 = reader.ReadByte();
				list.Add(new ZoneMarker
				{
					Position = position,
					Radius = radius,
					Dies = ((b2 & 1) != 0),
					StageWide = ((b2 & 2) != 0),
					Tube = ((b2 & 4) != 0)
				});
			}
			return list;
		}

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCHello(ConCommandArgs args)
		{
			//IL_0007: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active || !Object.op_Implicit((Object)(object)args.sender) || ((NetworkBehaviour)args.sender).isLocalPlayer)
			{
				return;
			}
			NetworkConnection connectionToClient = ((NetworkBehaviour)args.sender).connectionToClient;
			if (connectionToClient != null && connectionToClient.isConnected)
			{
				if (moddedConnections.Add(connectionToClient))
				{
					WhereToDiePlugin.Log.LogInfo((object)(args.sender.userName + " has WhereToDie."));
				}
				SendMarkers(connectionToClient);
			}
		}

		[NetworkMessageHandler(msgType = 22340, client = true)]
		private static void HandleMarkers(NetworkMessage netMsg)
		{
			if (!NetworkServer.active)
			{
				List<ZoneMarker> list = ReadMarkers(netMsg.reader);
				if (list != null)
				{
					HostHasMod = true;
					ZoneTracker.SetMarkers(list);
				}
			}
		}

		[ConCommand(/*Could not decode attribute arguments.*/)]
		private static void CCStatus(ConCommandArgs args)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			string arg = (NetworkServer.active ? "host" : (NetworkClient.active ? "client" : "offline"));
			Debug.Log((object)($"[WhereToDie] role={arg} hostHasMod={NetworkServer.active || HostHasMod} moddedClients={moddedConnections.Count} " + $"markers={ZoneTracker.Markers.Count} {PageFixes.StatusText()}"));
			foreach (ZoneMarker marker in ZoneTracker.Markers)
			{
				Debug.Log((object)$"[WhereToDie]   at {marker.Position} radius={marker.Radius:0.#} dies={marker.Dies} stageWide={marker.StageWide} tube={marker.Tube}");
			}
			if (!NetworkServer.active)
			{
				return;
			}
			foreach (string item in ZoneTracker.DescribeZones())
			{
				Debug.Log((object)("[WhereToDie]   zone " + item));
			}
		}
	}
	internal struct ZoneMarker : IEquatable<ZoneMarker>
	{
		internal Vector3 Position;

		internal float Radius;

		internal bool Dies;

		internal bool StageWide;

		internal bool Tube;

		internal bool Contains(Vector3 position)
		{
			//IL_000a: 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_0011: 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)
			if (StageWide)
			{
				return true;
			}
			Vector3 val = position - Position;
			if (Tube)
			{
				val.y = 0f;
			}
			return ((Vector3)(ref val)).sqrMagnitude <= Radius * Radius;
		}

		public bool Equals(ZoneMarker other)
		{
			//IL_0001: 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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Position - other.Position;
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f && Mathf.Abs(Radius - other.Radius) < 0.1f && Dies == other.Dies && StageWide == other.StageWide)
			{
				return Tube == other.Tube;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is ZoneMarker other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return ((object)Unsafe.As<Vector3, Vector3>(ref Position)/*cast due to .constrained prefix*/).GetHashCode() ^ Radius.GetHashCode();
		}
	}
	internal static class ZoneTracker
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static hook_OnPrePopulateSceneServer <0>__DLC4SacrificeZoneSpawner_OnPrePopulateSceneServer;

			public static Action <1>__OnFixedUpdate;
		}

		private const float StageWideRadius = 1000f;

		internal const float StageWideDuration = 30f;

		private const float PollInterval = 0.5f;

		private static FieldInfo useRerollField;

		private static FieldInfo useNextSceneField;

		private static FieldInfo useExplicitSceneField;

		private static FieldInfo explicitSceneField;

		private static FieldInfo pageRequirementField;

		private static readonly HashSet<CursedBookSacrificeZone> stageWideZones = new HashSet<CursedBookSacrificeZone>();

		private static float pollTimer;

		internal static readonly List<ZoneMarker> Markers = new List<ZoneMarker>();

		internal static event Action onMarkersChanged;

		internal static void Init()
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Expected O, but got Unknown
			Type? typeFromHandle = typeof(CursedBookSacrificeZone);
			useRerollField = typeFromHandle.GetField("useRerollSceneInstead", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			useNextSceneField = typeFromHandle.GetField("useNextSceneInstead", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			useExplicitSceneField = typeFromHandle.GetField("useExplicitSceneInstead", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			explicitSceneField = typeFromHandle.GetField("explicitScene", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			pageRequirementField = typeFromHandle.GetField("pageRequirement", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (useRerollField == null || useNextSceneField == null || useExplicitSceneField == null || explicitSceneField == null || pageRequirementField == null)
			{
				WhereToDiePlugin.Log.LogError((object)"CursedBookSacrificeZone fields not found; the aurora may show zones that don't work.");
			}
			object obj = <>O.<0>__DLC4SacrificeZoneSpawner_OnPrePopulateSceneServer;
			if (obj == null)
			{
				hook_OnPrePopulateSceneServer val = DLC4SacrificeZoneSpawner_OnPrePopulateSceneServer;
				<>O.<0>__DLC4SacrificeZoneSpawner_OnPrePopulateSceneServer = val;
				obj = (object)val;
			}
			DLC4SacrificeZoneSpawner.OnPrePopulateSceneServer += (hook_OnPrePopulateSceneServer)obj;
			RoR2Application.onFixedUpdate += OnFixedUpdate;
			Stage.onStageStartGlobal += delegate
			{
				stageWideZones.RemoveWhere((CursedBookSacrificeZone zone) => !Object.op_Implicit((Object)(object)zone));
			};
			Run.onRunDestroyGlobal += delegate
			{
				SetMarkers(new List<ZoneMarker>());
			};
		}

		private static void DLC4SacrificeZoneSpawner_OnPrePopulateSceneServer(orig_OnPrePopulateSceneServer orig, DLC4SacrificeZoneSpawner self, SceneDirector director)
		{
			HashSet<CursedBookSacrificeZone> hashSet = new HashSet<CursedBookSacrificeZone>(CursedBookSacrificeZone.instanceList);
			orig.Invoke(self, director);
			foreach (CursedBookSacrificeZone instance in CursedBookSacrificeZone.instanceList)
			{
				if (Object.op_Implicit((Object)(object)instance) && !hashSet.Contains(instance))
				{
					stageWideZones.Add(instance);
				}
			}
		}

		private static void OnFixedUpdate()
		{
			if (NetworkServer.active && Object.op_Implicit((Object)(object)Run.instance))
			{
				pollTimer -= Time.fixedDeltaTime;
				if (!(pollTimer > 0f))
				{
					pollTimer = 0.5f;
					SetMarkers(ComputeMarkers());
				}
			}
		}

		internal static void SetMarkers(List<ZoneMarker> markers)
		{
			if (markers.Count == Markers.Count)
			{
				bool flag = true;
				for (int i = 0; i < markers.Count && flag; i++)
				{
					flag = markers[i].Equals(Markers[i]);
				}
				if (flag)
				{
					return;
				}
			}
			Markers.Clear();
			Markers.AddRange(markers);
			if (NetworkServer.active)
			{
				ZoneNetwork.BroadcastMarkers();
			}
			ZoneTracker.onMarkersChanged?.Invoke();
		}

		private static List<ZoneMarker> ComputeMarkers()
		{
			List<ZoneMarker> list = new List<ZoneMarker>();
			foreach (CursedBookSacrificeZone instance in CursedBookSacrificeZone.instanceList)
			{
				if (IsActiveServer(instance) && TryMakeMarker(instance, out var marker))
				{
					AddOrMerge(list, marker);
				}
			}
			return list;
		}

		private static void AddOrMerge(List<ZoneMarker> markers, ZoneMarker marker)
		{
			//IL_001f: 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)
			if (!marker.StageWide)
			{
				for (int i = 0; i < markers.Count; i++)
				{
					ZoneMarker zoneMarker = markers[i];
					if (!zoneMarker.StageWide && (zoneMarker.Contains(marker.Position) || marker.Contains(zoneMarker.Position)))
					{
						ZoneMarker value = ((zoneMarker.Radius >= marker.Radius) ? zoneMarker : marker);
						value.Dies = zoneMarker.Dies || marker.Dies;
						markers[i] = value;
						return;
					}
				}
			}
			markers.Add(marker);
		}

		internal static IEnumerable<string> DescribeZones()
		{
			foreach (CursedBookSacrificeZone instance in CursedBookSacrificeZone.instanceList)
			{
				if (!Object.op_Implicit((Object)(object)instance))
				{
					continue;
				}
				string arg = "?";
				if (useRerollField != null && (bool)useRerollField.GetValue(instance))
				{
					arg = "reroll";
				}
				else if (useNextSceneField != null && (bool)useNextSceneField.GetValue(instance))
				{
					arg = "next stage";
				}
				else
				{
					object? obj = explicitSceneField?.GetValue(instance);
					SceneDef val = (SceneDef)((obj is SceneDef) ? obj : null);
					if (val != null && Object.op_Implicit((Object)(object)val))
					{
						arg = val.cachedName;
					}
				}
				yield return $"{((Object)instance).name} at {((Component)instance).transform.position} behaviour={instance.behaviour} active={IsActiveServer(instance)} " + $"pages={RequiredPageCount(instance)} -> {arg}";
			}
		}

		private static bool TryMakeMarker(CursedBookSacrificeZone zone, out ZoneMarker marker)
		{
			//IL_0011: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			marker = new ZoneMarker
			{
				Position = ((Component)zone).transform.position,
				Dies = ((int)zone.behaviour == 0)
			};
			SphereZone val = default(SphereZone);
			VerticalTubeZone val2 = default(VerticalTubeZone);
			CustomZone customZone = default(CustomZone);
			if (((Component)zone).TryGetComponent<SphereZone>(ref val))
			{
				marker.Radius = val.radius;
				marker.StageWide = val.isInverted || val.radius >= 1000f;
			}
			else if (((Component)zone).TryGetComponent<VerticalTubeZone>(ref val2))
			{
				marker.Radius = val2.radius;
				marker.Tube = true;
			}
			else if (((Component)zone).TryGetComponent<CustomZone>(ref customZone))
			{
				marker.Position = customZone.Center;
				marker.Radius = customZone.radius;
				marker.Tube = !float.IsNegativeInfinity(customZone.floorY);
			}
			else
			{
				BoxZone val3 = default(BoxZone);
				if (!((Component)zone).TryGetComponent<BoxZone>(ref val3))
				{
					return false;
				}
				Vector3 val4 = ((Component)zone).transform.lossyScale * 0.5f;
				Vector2 val5 = new Vector2(val4.x, val4.z);
				marker.Radius = ((Vector2)(ref val5)).magnitude;
			}
			if (stageWideZones.Contains(zone))
			{
				marker.StageWide = true;
			}
			if (marker.StageWide && Object.op_Implicit((Object)(object)Stage.instance))
			{
				FixedTimeStamp entryTime = Stage.instance.entryTime;
				if (((FixedTimeStamp)(ref entryTime)).timeSince > 30f)
				{
					return false;
				}
			}
			return true;
		}

		internal static bool IsActiveServer(CursedBookSacrificeZone zone)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)zone) || !((Component)zone).gameObject.activeInHierarchy || zone.isDisabled || !zone.runFlagConditionResult)
			{
				return false;
			}
			if (((Component)zone).GetComponent<IZone>() == null)
			{
				return false;
			}
			if ((int)zone.behaviour == 0 && !HasDestination(zone))
			{
				return false;
			}
			return Util.GetTotalPageCountFromTeam((TeamIndex)1, true, true) >= RequiredPageCount(zone);
		}

		private static bool HasDestination(CursedBookSacrificeZone zone)
		{
			if (useRerollField == null)
			{
				return true;
			}
			if ((bool)useRerollField.GetValue(zone))
			{
				return true;
			}
			if ((bool)useNextSceneField.GetValue(zone))
			{
				return Object.op_Implicit((Object)(object)Run.instance.nextStageScene);
			}
			if (!(bool)useExplicitSceneField.GetValue(zone))
			{
				return true;
			}
			object? value = explicitSceneField.GetValue(zone);
			SceneDef val = (SceneDef)((value is SceneDef) ? value : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				if (Object.op_Implicit((Object)(object)val.requiredExpansion))
				{
					return Run.instance.IsExpansionEnabled(val.requiredExpansion);
				}
				return true;
			}
			return false;
		}

		private static int RequiredPageCount(CursedBookSacrificeZone zone)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			if (pageRequirementField == null)
			{
				return 0;
			}
			PageRequirements val = (PageRequirements)pageRequirementField.GetValue(zone);
			if ((int)val != 1)
			{
				if ((int)val == 2)
				{
					return Util.ScalePageRequirement(6);
				}
				return 0;
			}
			return Util.ScalePageRequirement(3);
		}

		internal static bool? DiesAt(Vector3 position)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			foreach (CursedBookSacrificeZone instance in CursedBookSacrificeZone.instanceList)
			{
				if (Object.op_Implicit((Object)(object)instance) && ((Component)instance).gameObject.activeInHierarchy && !instance.isDisabled && instance.runFlagConditionResult && (!NetworkServer.active || IsActiveServer(instance)))
				{
					IZone component = ((Component)instance).GetComponent<IZone>();
					if (component != null && component.IsInBounds(position))
					{
						return (int)instance.behaviour == 0;
					}
				}
			}
			foreach (ZoneMarker marker in Markers)
			{
				if (marker.Contains(position))
				{
					return marker.Dies;
				}
			}
			return null;
		}
	}
}