Decompiled source of WaveSurvival v1.0.1

WaveSurvival.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Text.Json.Serialization;
using AIGraph;
using AK;
using Agents;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Enemies;
using GTFO.API;
using GTFO.API.Utilities;
using GameData;
using HarmonyLib;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using LevelGeneration;
using Localization;
using MTFO.API;
using MTFO.Ext.PartialData;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using TMPro;
using UnityEngine;
using WaveSurvival.Attributes;
using WaveSurvival.CustomWave;
using WaveSurvival.CustomWaveData;
using WaveSurvival.CustomWaveData.Wave;
using WaveSurvival.CustomWaveData.WaveObjective;
using WaveSurvival.Dependencies;
using WaveSurvival.Extensions;
using WaveSurvival.Json;
using WaveSurvival.Json.Converters;
using WaveSurvival.Json.Converters.Utils;
using WaveSurvival.Networking;
using WaveSurvival.Utils;
using WaveSurvival.Utils.Extensions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("WaveSurvival")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+edef27c729c591e17dd842fee3bbf1c9653150d9")]
[assembly: AssemblyProduct("WaveSurvival")]
[assembly: AssemblyTitle("WaveSurvival")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace WaveSurvival
{
	internal static class Configuration
	{
		private static ConfigEntry<KeyCode> _skipWaveBind;

		private static ConfigFile _configFile;

		public static KeyCode SkipWaveBind => _skipWaveBind.Value;

		internal static void Init()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			_configFile = new ConfigFile(Path.Combine(Paths.ConfigPath, "WaveSurvival.cfg"), true);
			string text = "Keybinds";
			_skipWaveBind = _configFile.Bind<KeyCode>(text, "Skip Wave Keybind", (KeyCode)120, "The keybind to skip the wait until the next wave (host only).");
			LiveEdit.CreateListener(Paths.ConfigPath, "WaveSurvival.cfg", false).FileChanged += new LiveEditEventHandler(OnFileChanged);
		}

		private static void OnFileChanged(LiveEditEventArgs _)
		{
			_configFile.Reload();
		}
	}
	internal static class DinoLogger
	{
		private static ManualLogSource _logger = Logger.CreateLogSource("WaveSurvival");

		public static void Log(string format, params object[] args)
		{
			Log(string.Format(format, args));
		}

		public static void Log(string str)
		{
			if (_logger != null)
			{
				_logger.Log((LogLevel)8, (object)str);
			}
		}

		public static void Warning(string format, params object[] args)
		{
			Warning(string.Format(format, args));
		}

		public static void Warning(string str)
		{
			if (_logger != null)
			{
				_logger.Log((LogLevel)4, (object)str);
			}
		}

		public static void Error(string format, params object[] args)
		{
			Error(string.Format(format, args));
		}

		public static void Error(string str)
		{
			if (_logger != null)
			{
				_logger.Log((LogLevel)2, (object)str);
			}
		}

		public static void Debug(string format, params object[] args)
		{
			Debug(string.Format(format, args));
		}

		public static void Debug(string str)
		{
			if (_logger != null)
			{
				_logger.Log((LogLevel)32, (object)str);
			}
		}
	}
	[BepInPlugin("Dinorush.WaveSurvival", "WaveSurvival", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class EntryPoint : BasePlugin
	{
		public const string MODNAME = "WaveSurvival";

		public const string AUTHOR = "Dinorush";

		public const string GUID = "Dinorush.WaveSurvival";

		public const string VERSION = "1.0.0";

		private IEnumerable<MethodInfo> _cleanupCallbacks;

		private IEnumerable<MethodInfo> _enterCallbacks;

		private IEnumerable<MethodInfo> _buildStartCallbacks;

		private IEnumerable<MethodInfo> _buildDoneCallbacks;

		public override void Load()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			CacheFrequentCallbacks();
			LevelAPI.OnLevelCleanup += RunFrequentCallback(_cleanupCallbacks);
			LevelAPI.OnEnterLevel += RunFrequentCallback(_enterCallbacks);
			LevelAPI.OnBuildStart += RunFrequentCallback(_buildStartCallbacks);
			LevelAPI.OnBuildDone += RunFrequentCallback(_buildDoneCallbacks);
			new Harmony("WaveSurvival").PatchAll();
			AssetAPI.OnStartupAssetsLoaded += InvokeCallbacks<InvokeOnAssetsLoadedAttribute>;
			Configuration.Init();
			InvokeCallbacks<InvokeOnLoadAttribute>();
			DinoLogger.Log("Loaded WaveSurvival");
		}

		private static Action RunFrequentCallback(IEnumerable<MethodInfo> callbacks)
		{
			IEnumerable<MethodInfo> callbacks2 = callbacks;
			return delegate
			{
				foreach (MethodInfo item in callbacks2)
				{
					item.Invoke(null, null);
				}
			};
		}

		private void CacheFrequentCallbacks()
		{
			IEnumerable<MethodInfo> source = from method in ((IEnumerable<Type>)AccessTools.GetTypesFromAssembly(((object)this).GetType().Assembly)).SelectMany((Func<Type, IEnumerable<MethodInfo>>)AccessTools.GetDeclaredMethods)
				where method.IsStatic
				select method;
			var source2 = from method in source
				let attr = method.GetCustomAttribute<InvokeOnCleanupAttribute>()
				where attr != null
				select new
				{
					Method = method,
					Attribute = attr
				};
			_cleanupCallbacks = source2.Select(pair => pair.Method);
			_enterCallbacks = source.Where((MethodInfo method) => method.GetCustomAttribute<InvokeOnEnterAttribute>() != null);
			_buildStartCallbacks = source.Where((MethodInfo method) => method.GetCustomAttribute<InvokeOnBuildStartAttribute>() != null);
			_buildDoneCallbacks = source.Where((MethodInfo method) => method.GetCustomAttribute<InvokeOnBuildDoneAttribute>() != null);
		}

		private void InvokeCallbacks<T>() where T : Attribute
		{
			foreach (MethodInfo item in from method in ((IEnumerable<Type>)AccessTools.GetTypesFromAssembly(((object)this).GetType().Assembly)).SelectMany((Func<Type, IEnumerable<MethodInfo>>)AccessTools.GetDeclaredMethods)
				where method.IsStatic && method.GetCustomAttribute<T>() != null
				select method)
			{
				item.Invoke(null, null);
			}
		}
	}
}
namespace WaveSurvival.Extensions
{
	public static class CellSoundPlayerExt
	{
		public static uint PostWithCleanup(this CellSoundPlayer soundPlayer, uint eventID, Vector3 pos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return soundPlayer.Post(eventID, pos, 1u, EventCallback.op_Implicit((Action<Object, AkCallbackType, AkCallbackInfo>)SoundDoneCallback), (Object)(object)soundPlayer);
		}

		public static void SoundDoneCallback(Object in_cookie, AkCallbackType in_type, AkCallbackInfo callbackInfo)
		{
			CellSoundPlayer obj = ((Il2CppObjectBase)in_cookie).Cast<CellSoundPlayer>();
			if (obj != null)
			{
				obj.Recycle();
			}
		}
	}
}
namespace WaveSurvival.Utils
{
	internal class EmptyList<T>
	{
		public static readonly List<T> Instance = new List<T>();
	}
	[JsonConverter(typeof(LocaleTextConverter))]
	public struct LocaleText : IEquatable<LocaleText>
	{
		public uint ID;

		public string RawText;

		public static readonly LocaleText Empty = new LocaleText(string.Empty);

		private readonly string TextFallback
		{
			get
			{
				if (ID != 0)
				{
					return Text.Get(ID);
				}
				return RawText;
			}
		}

		public LocaleText(LocalizedText baseText)
		{
			ID = 0u;
			RawText = string.Empty;
			RawText = LocalizedToText(baseText);
			ID = baseText.Id;
		}

		public LocaleText(string text)
		{
			ID = 0u;
			RawText = string.Empty;
			if (PartialData.TryGetGUID(text, out var guid))
			{
				RawText = string.Empty;
				ID = guid;
			}
			else
			{
				RawText = text;
				ID = 0u;
			}
		}

		public LocaleText(uint id)
		{
			ID = 0u;
			RawText = string.Empty;
			RawText = string.Empty;
			ID = id;
		}

		public readonly LocalizedText ToLocalizedText()
		{
			//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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			return new LocalizedText
			{
				Id = ID,
				UntranslatedText = TextFallback
			};
		}

		public override readonly string ToString()
		{
			return TextFallback;
		}

		public static string LocalizedToText(LocalizedText text)
		{
			if (!text.HasTranslation)
			{
				return text.UntranslatedText;
			}
			return Text.Get(text.Id);
		}

		public static explicit operator LocaleText(LocalizedText localizedText)
		{
			return new LocaleText(localizedText);
		}

		public static explicit operator LocaleText(string text)
		{
			return new LocaleText(text);
		}

		public static implicit operator LocalizedText(LocaleText localeText)
		{
			return localeText.ToLocalizedText();
		}

		public static implicit operator string(LocaleText localeText)
		{
			return localeText.ToString();
		}

		public readonly bool Equals(LocaleText other)
		{
			if (ID == other.ID)
			{
				return string.Equals(RawText, other.RawText, StringComparison.Ordinal);
			}
			return false;
		}

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

		public override readonly int GetHashCode()
		{
			return HashCode.Combine(ID, RawText);
		}

		public static bool operator ==(LocaleText left, LocaleText right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(LocaleText left, LocaleText right)
		{
			return !(left == right);
		}
	}
	[JsonConverter(typeof(WeightedListConverterFactory))]
	public sealed class WeightedList<T> : IEnumerable<T>, IEnumerable where T : IWeightable
	{
		private class Node
		{
			public T Value { get; set; }

			public float Weight { get; set; }

			public float TotalWeight { get; set; }

			public Node(T value)
			{
				Value = value;
				Weight = value.Weight;
				TotalWeight = Weight;
			}
		}

		public static readonly WeightedList<T> Empty = new WeightedList<T>();

		private static readonly Random s_random = new Random();

		private List<Node> _heap = EmptyList<Node>.Instance;

		private List<T> _values = EmptyList<T>.Instance;

		private bool _isDirty;

		public List<T> Values
		{
			get
			{
				return _values;
			}
			set
			{
				_values = value;
				_isDirty = true;
			}
		}

		private List<Node> Heap
		{
			get
			{
				if (_isDirty)
				{
					_isDirty = false;
					GenerateHeap();
				}
				return _heap;
			}
		}

		public T this[int index]
		{
			get
			{
				return _values[index];
			}
			set
			{
				_values[index] = value;
				_isDirty = true;
			}
		}

		public int Count => Values.Count;

		public WeightedList()
		{
		}

		public WeightedList(List<T> list)
		{
			Values = list;
		}

		public static implicit operator WeightedList<T>?(List<T>? list)
		{
			if (list == null)
			{
				return null;
			}
			return new WeightedList<T>(list);
		}

		public static implicit operator List<T>?(WeightedList<T>? weightedList)
		{
			return weightedList?.Values;
		}

		public void Add(T value)
		{
			if (Count == 0)
			{
				_values = new List<T>();
			}
			_values.Add(value);
			_isDirty = true;
		}

		public void Remove(T value)
		{
			if (Count != 0)
			{
				_isDirty = _values.Remove(value);
			}
		}

		public void RemoveAt(int index)
		{
			if (Count != 0)
			{
				_isDirty = true;
				_values.RemoveAt(index);
			}
		}

		public int RemoveAll(Predicate<T> predicate)
		{
			int num = _values.RemoveAll(predicate);
			if (num != 0)
			{
				_isDirty = true;
			}
			return num;
		}

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

		IEnumerator<T> IEnumerable<T>.GetEnumerator()
		{
			return _values.GetEnumerator();
		}

		public bool TryGetRandom([MaybeNullWhen(false)] out T obj)
		{
			if (Count == 0 || Heap[1].TotalWeight == 0f)
			{
				obj = default(T);
				return false;
			}
			obj = PopFromHeap();
			return true;
		}

		public T GetRandom()
		{
			if (Count == 0)
			{
				throw new IndexOutOfRangeException("Can't get random element from 0-length list!");
			}
			if (Heap[1].TotalWeight == 0f)
			{
				RefillHeap();
			}
			return PopFromHeap();
		}

		public void Refill()
		{
			if (Count != 0 && !_isDirty)
			{
				RefillHeap();
			}
		}

		private void GenerateHeap()
		{
			_heap = new List<Node>(Count + 1) { null };
			foreach (T value in _values)
			{
				_heap.Add(new Node(value));
			}
			for (int num = Heap.Count - 1; num > 1; num--)
			{
				_heap[num >> 1].TotalWeight += _heap[num].TotalWeight;
			}
		}

		private void RefillHeap()
		{
			for (int i = 1; i < Heap.Count; i++)
			{
				Heap[i].Weight = _values[i - 1].Weight;
				Heap[i].TotalWeight = _values[i - 1].Weight;
			}
			for (int num = Heap.Count - 1; num > 1; num--)
			{
				Heap[num >> 1].TotalWeight += Heap[num].TotalWeight;
			}
		}

		private T PopFromHeap()
		{
			if (Heap[1].TotalWeight == 0f)
			{
				throw new IndexOutOfRangeException("Cannot get an element from WeightedShuffleList with 0 total weight remaining!");
			}
			if (Count == 1)
			{
				return _values[0];
			}
			float num = s_random.NextSingle(Heap[1].TotalWeight);
			int num2 = 1;
			while (num >= Heap[num2].Weight)
			{
				num -= Heap[num2].Weight;
				num2 <<= 1;
				if (num >= Heap[num2].TotalWeight)
				{
					num -= Heap[num2].TotalWeight;
					num2++;
				}
			}
			float weight = Heap[num2].Weight;
			T value = Heap[num2].Value;
			Heap[num2].Weight = 0f;
			while (num2 > 0)
			{
				Heap[num2].TotalWeight -= weight;
				num2 >>= 1;
			}
			return value;
		}
	}
	public interface IWeightable
	{
		float Weight { get; }
	}
}
namespace WaveSurvival.Utils.Extensions
{
	internal static class EnemyAgentExt
	{
		public static void AddOnDeadOnce(this EnemyAgent agent, Action onDead)
		{
			Action onDead2 = onDead;
			bool called = false;
			agent.OnDeadCallback += Action.op_Implicit((Action)delegate
			{
				if (!called && !CheckpointManager.IsReloadingCheckpoint)
				{
					onDead2?.Invoke();
					called = true;
				}
			});
		}
	}
	internal static class RandomExt
	{
		public static void Shuffle<T>(this Random random, T[] values)
		{
			int num = values.Length;
			for (int i = 0; i < num - 1; i++)
			{
				int num2 = random.Next(i, num);
				if (num2 != i)
				{
					int num3 = num2;
					int num4 = i;
					T val = values[i];
					T val2 = values[num2];
					values[num3] = val;
					values[num4] = val2;
				}
			}
		}

		public static float NextSingle(this Random random, float maxValue)
		{
			return random.NextSingle() * maxValue;
		}

		public static float NextSingle(this Random random, float minValue, float maxValue)
		{
			return random.NextSingle() * (maxValue - minValue) + minValue;
		}
	}
	internal static class StringExt
	{
		public static T ToEnum<T>(this string? value, T defaultValue) where T : struct
		{
			if (string.IsNullOrEmpty(value))
			{
				return defaultValue;
			}
			if (!Enum.TryParse<T>(value.Replace(" ", null), ignoreCase: true, out var result))
			{
				return defaultValue;
			}
			return result;
		}
	}
}
namespace WaveSurvival.Patches
{
	[HarmonyPatch]
	internal static class CheckpointPatches
	{
		private static Vector3 _lastCheckpointPos = Vector3.zero;

		[HarmonyPatch(typeof(CheckpointManager), "OnStateChange")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		public static void OnCheckpointStateChange(pCheckpointState newState)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_002c: 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_0033: Invalid comparison between Unknown and I4
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if ((int)newState.lastInteraction == 1 && _lastCheckpointPos != newState.doorLockPosition)
			{
				_lastCheckpointPos = newState.doorLockPosition;
				WaveManager.Internal_OnCheckpointReached();
			}
			else if ((int)newState.lastInteraction == 2)
			{
				WaveManager.Internal_OnCheckpointReload();
			}
		}

		[InvokeOnCleanup]
		private static void OnCleanup()
		{
			//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)
			_lastCheckpointPos = Vector3.zero;
		}
	}
	[HarmonyPatch]
	internal static class DoorPatches
	{
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static void OnDoorStateChanged(LG_Gate __instance, ref bool __state)
		{
			__state = __instance.IsTraversable;
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void OnDoorStateChanged(LG_Gate __instance, bool __state)
		{
			if (__instance.IsTraversable != __state)
			{
				iLG_Door_Core spawnedDoor = __instance.SpawnedDoor;
				if (!((Object)(object)((spawnedDoor != null) ? ((Il2CppObjectBase)spawnedDoor).TryCast<LG_SecurityDoor>() : null) == (Object)null))
				{
					ZoneTree.Internal_OnDoorStateChanged(__instance, !__state);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class GuiPatches
	{
		[HarmonyPatch(typeof(GuiManager), "Setup")]
		[HarmonyPostfix]
		private static void AddNewLayer()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			PUI_ObjectiveTimer waveInfo = ((Il2CppObjectBase)((GuiLayer)GuiManager.PlayerLayer).AddComp("Gui/Player/PUI_ObjectiveTimer", (GuiAnchor)3, new Vector2(0f, 425f), (Transform)null)).Cast<PUI_ObjectiveTimer>();
			PUI_InteractionPrompt intPrompt = ((Il2CppObjectBase)((GuiLayer)GuiManager.InteractionLayer).AddRectComp("Gui/Player/PUI_InteractionPrompt_CellUI", (GuiAnchor)3, new Vector2(0f, 375f), (Transform)null)).Cast<PUI_InteractionPrompt>();
			WaveText.Internal_Setup(waveInfo, intPrompt);
		}
	}
	[HarmonyPatch]
	internal static class LobbyPatches
	{
		[HarmonyPatch(typeof(SNet_SyncManager), "OnPlayerJoinedSessionHub")]
		[HarmonyPostfix]
		private static void Post_Joined(SNet_Player player)
		{
			if (WaveManager.TryGetActiveObjective(out WaveObjectiveData objective))
			{
				WaveNetwork.SendObjective(objective, player);
			}
		}
	}
	[HarmonyPatch]
	internal static class WarpPatches
	{
		[HarmonyPatch(typeof(PlayerAgent), "WarpTo")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void PreWarp(PlayerAgent __instance, ref eDimensionIndex __state)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected I4, but got Unknown
			__state = (eDimensionIndex)(int)((Agent)__instance).DimensionIndex;
		}

		[HarmonyPatch(typeof(PlayerAgent), "WarpTo")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void OnWarp(PlayerAgent __instance, eDimensionIndex __state)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			eDimensionIndex dimensionIndex = ((Agent)__instance).DimensionIndex;
			if (__state != dimensionIndex)
			{
				WaveManager.Internal_OnWarp(dimensionIndex);
			}
		}
	}
	[HarmonyPatch]
	internal class Patch_CheckAndExecuteEventsOnTrigger
	{
		[HarmonyPrefix]
		[HarmonyWrapSafe]
		[HarmonyPatch(typeof(WardenObjectiveManager), "CheckAndExecuteEventsOnTrigger", new Type[]
		{
			typeof(WardenObjectiveEventData),
			typeof(eWardenObjectiveEventTrigger),
			typeof(bool),
			typeof(float)
		})]
		private static void Pre_CheckAndExecuteEventsOnTrigger(WardenObjectiveEventData eventToTrigger, eWardenObjectiveEventTrigger trigger, bool ignoreTrigger, float currentDuration)
		{
			//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_0027: Unknown result type (might be due to invalid IL or missing references)
			if (eventToTrigger != null && (ignoreTrigger || eventToTrigger.Trigger == trigger) && ((double)currentDuration == 0.0 || !(eventToTrigger.Delay <= currentDuration)))
			{
				WaveManager.Internal_OnWardenEvent(eventToTrigger.Type);
			}
		}
	}
}
namespace WaveSurvival.Networking
{
	public abstract class SyncedEvent<T> where T : struct
	{
		public delegate void ReceiveHandler(T packet);

		private bool _isSetup;

		public abstract string GUID { get; }

		public bool IsSetup => _isSetup;

		public string EventName { get; private set; } = string.Empty;


		public event ReceiveHandler? OnReceive;

		public event ReceiveHandler? OnReceiveLocal;

		public void Setup()
		{
			if (!_isSetup)
			{
				EventName = "SIM" + GUID;
				NetworkAPI.RegisterEvent<T>(EventName, (Action<ulong, T>)ReceiveClient_Callback);
				_isSetup = true;
			}
		}

		public void Send(T packetData, SNet_Player? target = null, SNet_ChannelType priority = 4)
		{
			//IL_0020: 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)
			if ((Object)(object)target != (Object)null)
			{
				NetworkAPI.InvokeEvent<T>(EventName, packetData, target, priority);
			}
			else
			{
				NetworkAPI.InvokeEvent<T>(EventName, packetData, priority);
			}
			ReceiveLocal_Callback(packetData);
		}

		private void ReceiveLocal_Callback(T packet)
		{
			ReceiveLocal(packet);
			this.OnReceiveLocal?.Invoke(packet);
		}

		private void ReceiveClient_Callback(ulong sender, T packet)
		{
			Receive(packet);
			this.OnReceive?.Invoke(packet);
		}

		protected virtual void ReceiveLocal(T packet)
		{
		}

		protected virtual void Receive(T packet)
		{
		}
	}
	public abstract class SyncedEventMasterOnly<T> : SyncedEvent<T> where T : struct
	{
		public void Send(T packet, SNet_ChannelType priority = 4)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (!SNet.IsMaster)
			{
				Send(packet, SNet.Master, priority);
			}
			else
			{
				Receive(packet);
			}
		}
	}
}
namespace WaveSurvival.Json
{
	public static class JSON
	{
		private static readonly JsonSerializerOptions _setting;

		static JSON()
		{
			_setting = new JsonSerializerOptions
			{
				ReadCommentHandling = JsonCommentHandling.Skip,
				IncludeFields = true,
				PropertyNameCaseInsensitive = true,
				WriteIndented = true,
				IgnoreReadOnlyProperties = true
			};
			_setting.Converters.Add(new JsonStringEnumConverter());
			_setting.Converters.Add(new OptionalListConverter<WaveObjectiveData>());
		}

		public static T? Deserialize<T>(string json)
		{
			return JsonSerializer.Deserialize<T>(json, _setting);
		}

		public static T? Deserialize<T>(ref Utf8JsonReader reader)
		{
			return JsonSerializer.Deserialize<T>(ref reader, _setting);
		}

		public static bool TryDeserializeSafe<T>(string json, [MaybeNullWhen(false)] out T value)
		{
			try
			{
				value = JsonSerializer.Deserialize<T>(json, _setting);
				return value != null;
			}
			catch (JsonException ex)
			{
				DinoLogger.Error("Caught exception while reading json: " + ex.Message + "\n" + ex.StackTrace);
				value = default(T);
				return false;
			}
		}

		public static bool TryDeserialize<T>(string json, [MaybeNullWhen(false)] out T value)
		{
			value = JsonSerializer.Deserialize<T>(json, _setting);
			return value != null;
		}

		public static bool TryDeserialize<T>(ref Utf8JsonReader reader, [MaybeNullWhen(false)] out T value)
		{
			value = JsonSerializer.Deserialize<T>(ref reader, _setting);
			return value != null;
		}

		public static object? Deserialize(Type type, string json)
		{
			return JsonSerializer.Deserialize(json, type, _setting);
		}

		public static string Serialize<T>(T value)
		{
			return JsonSerializer.Serialize(value, _setting);
		}

		public static void Serialize<T>(Utf8JsonWriter writer, T value)
		{
			JsonSerializer.Serialize(writer, value, _setting);
		}

		public static void Serialize<T>(Utf8JsonWriter writer, string name, T value)
		{
			writer.WritePropertyName(name);
			JsonSerializer.Serialize(writer, value, _setting);
		}
	}
	[JsonConverter(typeof(JsonReferenceConverterFactory))]
	public class JsonReference<T> where T : new()
	{
		public virtual T? Value { get; set; }

		public string ID { get; set; } = string.Empty;


		public JsonReference()
		{
		}

		public JsonReference(T? obj)
		{
			Value = obj;
		}

		public JsonReference(string id)
		{
			ID = id;
		}

		public static implicit operator T(JsonReference<T> r)
		{
			if (r.Value != null)
			{
				return r.Value;
			}
			throw new InvalidOperationException(typeof(T).Name + " reference has not been resolved (" + r.ID + ")");
		}
	}
}
namespace WaveSurvival.Json.Converters
{
	public sealed class JsonReferenceConverterFactory : JsonConverterFactory
	{
		public override bool CanConvert(Type typeToConvert)
		{
			if (!typeToConvert.IsGenericType)
			{
				return false;
			}
			return typeToConvert.GetGenericTypeDefinition().IsAssignableTo(typeof(JsonReference<>));
		}

		public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
		{
			Type type = typeToConvert.GetGenericArguments()[0];
			return (JsonConverter)Activator.CreateInstance(typeof(JsonReferenceConverter<>).MakeGenericType(type));
		}
	}
	public sealed class JsonReferenceConverter<T> : JsonConverter<JsonReference<T>> where T : new()
	{
		public override bool HandleNull => true;

		public override JsonReference<T>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			return reader.TokenType switch
			{
				JsonTokenType.Null => new JsonReference<T>(), 
				JsonTokenType.String => new JsonReference<T>(JsonSerializer.Deserialize<string>(ref reader, options)), 
				_ => new JsonReference<T>(JsonSerializer.Deserialize<T>(ref reader, options)), 
			};
		}

		public override void Write(Utf8JsonWriter writer, JsonReference<T>? value, JsonSerializerOptions options)
		{
			if (value == null)
			{
				writer.WriteNullValue();
			}
			else if (value.Value != null)
			{
				JsonSerializer.Serialize(writer, value.Value, options);
			}
			else if (!string.IsNullOrEmpty(value.ID))
			{
				JsonSerializer.Serialize(writer, value.ID, options);
			}
			else
			{
				JsonSerializer.Serialize(writer, new T(), options);
			}
		}
	}
	public sealed class LevelTargetConverter : JsonConverter<LevelTarget>
	{
		public override bool HandleNull => true;

		public override LevelTarget? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			LevelTarget levelTarget = new LevelTarget();
			if (ParseTarget(ref reader, levelTarget, options))
			{
				return levelTarget;
			}
			throw new JsonException("Expected level target to be a tier, tierindex, or level layout ID");
		}

		private static bool ParseTarget(ref Utf8JsonReader reader, LevelTarget target, JsonSerializerOptions options)
		{
			//IL_005b: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Invalid comparison between Unknown and I4
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Invalid comparison between Unknown and I4
			if (reader.TokenType == JsonTokenType.Null)
			{
				return true;
			}
			if (reader.TokenType == JsonTokenType.String)
			{
				string @string = reader.GetString();
				if (@string.Length >= 5)
				{
					target.Tier = @string.Substring(0, 5).ToEnum<eRundownTier>((eRundownTier)99);
				}
				else
				{
					target.Tier = ("Tier" + @string[0]).ToEnum<eRundownTier>((eRundownTier)99);
				}
				int num = ((@string.Length < 5) ? 1 : 5);
				if ((int)target.Tier != 99 && @string.Length > num)
				{
					string text = @string;
					int num2 = num;
					if (int.TryParse(text.Substring(num2, text.Length - num2), out var result))
					{
						target.TierIndex = result - 1;
					}
					else
					{
						target.Tier = (eRundownTier)99;
					}
				}
				if ((int)target.Tier == 99)
				{
					target.LevelLayoutID = JsonSerializer.Deserialize<uint>(ref reader, options);
				}
				return true;
			}
			if (reader.TokenType == JsonTokenType.Number)
			{
				target.LevelLayoutID = reader.GetUInt32();
				return true;
			}
			return false;
		}

		public override void Write(Utf8JsonWriter writer, LevelTarget? value, JsonSerializerOptions options)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (value == null || (value.LevelLayoutID == 0 && (int)value.Tier == 99))
			{
				writer.WriteNullValue();
				return;
			}
			if (value.LevelLayoutID != 0)
			{
				writer.WriteNumberValue(value.LevelLayoutID);
				return;
			}
			eRundownTier tier = value.Tier;
			string? text = ((object)(eRundownTier)(ref tier)).ToString();
			writer.WriteStringValue(text[text.Length - 1] + ((value.TierIndex >= 0) ? (value.TierIndex + 1).ToString() : ""));
		}
	}
	public sealed class SpawnDataConverter : JsonConverter<SpawnData>
	{
		public override SpawnData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			SpawnData spawnData = new SpawnData();
			if (reader.TokenType == JsonTokenType.Number)
			{
				WeightedEnemyData item = new WeightedEnemyData
				{
					ID = reader.GetUInt32()
				};
				spawnData.Enemies = new JsonReference<List<WeightedEnemyData>>(new List<WeightedEnemyData> { item });
				return spawnData;
			}
			if (reader.TokenType != JsonTokenType.StartObject)
			{
				throw new JsonException("Expected number/list/object when reading a SpawnData object");
			}
			while (reader.Read())
			{
				if (reader.TokenType == JsonTokenType.EndObject)
				{
					return spawnData;
				}
				if (reader.TokenType != JsonTokenType.PropertyName)
				{
					throw new JsonException("Expected PropertyName when reading SpawnData object");
				}
				string text = reader.GetString().ToLower();
				reader.Read();
				switch (text)
				{
				case "enemies":
				{
					if (JSON.TryDeserialize<JsonReference<List<WeightedEnemyData>>>(ref reader, out var value2))
					{
						spawnData.Enemies = value2;
					}
					break;
				}
				case "count":
					spawnData.Count = reader.GetInt32();
					break;
				case "spawnrate":
					spawnData.SpawnRate = reader.GetSingle();
					break;
				case "spawninterval":
					spawnData.SpawnInterval = reader.GetInt32();
					break;
				case "spawndelayoninterval":
					spawnData.SpawnDelayOnInterval = reader.GetSingle();
					break;
				case "randomdirectionchanceoninterval":
					spawnData.RandomDirectionChanceOnInterval = reader.GetSingle();
					break;
				case "subwavemaxcount":
					spawnData.SubWaveMaxCount = reader.GetInt32();
					break;
				case "subwavedelay":
					spawnData.SubWaveDelay = reader.GetSingle();
					break;
				case "randomdirectionchance":
					spawnData.RandomDirectionChance = reader.GetSingle();
					break;
				case "eventsonsubwavestart":
				{
					if (JSON.TryDeserialize<List<WardenObjectiveEventData>>(ref reader, out var value))
					{
						spawnData.EventsOnSubWaveStart = value;
					}
					break;
				}
				case "subwavescreamsize":
					spawnData.SubWaveScreamSize = JsonSerializer.Deserialize<ScreamSize>(ref reader, options);
					break;
				case "subwavescreamtype":
					spawnData.SubWaveScreamType = JsonSerializer.Deserialize<ScreamType>(ref reader, options);
					break;
				case "hidefromtotalcount":
					spawnData.HideFromTotalCount = reader.GetBoolean();
					break;
				}
			}
			throw new JsonException("Expected EndObject when reading SpawnData object");
		}

		public override void Write(Utf8JsonWriter writer, SpawnData? value, JsonSerializerOptions options)
		{
			if (value == null)
			{
				writer.WriteNullValue();
				return;
			}
			writer.WriteStartObject();
			JSON.Serialize(writer, "Enemies", value.Enemies);
			writer.WriteNumber("Count", value.Count);
			writer.WriteNumber("SpawnRate", value.SpawnRate);
			writer.WriteNumber("SpawnInterval", value.SpawnInterval);
			writer.WriteNumber("SpawnDelayOnInterval", value.SpawnDelayOnInterval);
			writer.WriteNumber("RandomDirectionChanceOnInterval", value.RandomDirectionChanceOnInterval);
			writer.WriteNumber("SubWaveMaxCount", value.SubWaveMaxCount);
			writer.WriteNumber("SubWaveDelay", value.SubWaveDelay);
			writer.WriteNumber("RandomDirectionChance", value.RandomDirectionChance);
			JSON.Serialize(writer, "EventsOnSubWaveStart", value.EventsOnSubWaveStart);
			writer.WriteString("SubWaveScreamSize", value.SubWaveScreamSize.ToString());
			writer.WriteString("SubWaveScreamType", value.SubWaveScreamType.ToString());
			writer.WriteBoolean("HideFromTotalCount", value.HideFromTotalCount);
			writer.WriteEndObject();
		}
	}
	public sealed class SpawnPathDataConverter : JsonConverter<SpawnPathData>
	{
		public override SpawnPathData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			SpawnPathData spawnPathData = new SpawnPathData();
			if (reader.TokenType == JsonTokenType.Number)
			{
				spawnPathData.ZoneIndex = (eLocalZoneIndex)reader.GetInt32();
				return spawnPathData;
			}
			if (reader.TokenType != JsonTokenType.StartArray)
			{
				throw new JsonException("Expected number/list when reading a SpawnPath object");
			}
			reader.Read();
			if (reader.TokenType != JsonTokenType.Number)
			{
				throw new JsonException("Expected local index when reading a SpawnPath object");
			}
			spawnPathData.ZoneIndex = (eLocalZoneIndex)reader.GetInt32();
			reader.Read();
			if (reader.TokenType == JsonTokenType.EndArray)
			{
				return spawnPathData;
			}
			if (reader.TokenType != JsonTokenType.Number)
			{
				throw new JsonException("Expected area index when reading a SpawnPath object");
			}
			spawnPathData.AreaIndex = reader.GetInt32();
			reader.Read();
			if (reader.TokenType == JsonTokenType.EndArray)
			{
				return spawnPathData;
			}
			if (reader.TokenType != JsonTokenType.Number)
			{
				throw new JsonException("Expected layer when reading a SpawnPath object");
			}
			spawnPathData.Layer = (LG_LayerType)(byte)reader.GetInt32();
			reader.Read();
			if (reader.TokenType != JsonTokenType.EndArray)
			{
				throw new JsonException("Expected EndArray when reading SpawnPath object");
			}
			return spawnPathData;
		}

		public override void Write(Utf8JsonWriter writer, SpawnPathData? value, JsonSerializerOptions options)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected I4, but got Unknown
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected I4, but got Unknown
			if (value == null)
			{
				writer.WriteNullValue();
				return;
			}
			if (value.AreaIndex == -1)
			{
				writer.WriteNumberValue((int)value.ZoneIndex);
				return;
			}
			writer.WriteStartArray();
			writer.WriteNumberValue((int)value.ZoneIndex);
			writer.WriteNumberValue(value.AreaIndex);
			writer.WriteEndArray();
		}
	}
	public sealed class WaveDataConverter : JsonConverter<WaveData>
	{
		public override WaveData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			WaveData waveData = new WaveData();
			if (reader.TokenType != JsonTokenType.StartObject)
			{
				throw new JsonException("Expected object when reading a WaveData object");
			}
			while (reader.Read())
			{
				if (reader.TokenType == JsonTokenType.EndObject)
				{
					return waveData;
				}
				if (reader.TokenType != JsonTokenType.PropertyName)
				{
					throw new JsonException("Expected PropertyName when reading WaveData object");
				}
				string text = reader.GetString().ToLower();
				reader.Read();
				switch (text)
				{
				case "spawns":
				{
					List<JsonReference<SpawnData>> value2;
					if (reader.TokenType == JsonTokenType.Number)
					{
						if (JSON.TryDeserialize<JsonReference<SpawnData>>(ref reader, out var value))
						{
							waveData.Spawns = new List<JsonReference<SpawnData>> { value };
						}
					}
					else if (JSON.TryDeserialize<List<JsonReference<SpawnData>>>(ref reader, out value2))
					{
						waveData.Spawns = value2;
					}
					break;
				}
				case "waveheader":
					waveData.WaveHeader = JsonSerializer.Deserialize<LocaleText>(ref reader, options);
					break;
				case "screamsize":
					waveData.ScreamSize = JsonSerializer.Deserialize<ScreamSize>(ref reader, options);
					break;
				case "screamtype":
					waveData.ScreamType = JsonSerializer.Deserialize<ScreamType>(ref reader, options);
					break;
				}
			}
			throw new JsonException("Expected EndObject when reading SpawnData object");
		}

		public override void Write(Utf8JsonWriter writer, WaveData? value, JsonSerializerOptions options)
		{
			if (value == null)
			{
				writer.WriteNullValue();
				return;
			}
			writer.WriteStartObject();
			JSON.Serialize(writer, "Spawns", value.Spawns);
			writer.WriteString("WaveHeader", value.WaveHeader);
			writer.WriteString("ScreamSize", value.ScreamSize.ToString());
			writer.WriteString("ScreamType", value.ScreamType.ToString());
			writer.WriteEndObject();
		}
	}
	public sealed class WaveGroupConverter : JsonConverter<WaveGroupData>
	{
		public override WaveGroupData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			WaveGroupData waveGroupData = new WaveGroupData();
			if (reader.TokenType != JsonTokenType.StartObject)
			{
				throw new JsonException("Expected StartObject when reading WaveGroup");
			}
			while (reader.Read())
			{
				if (reader.TokenType == JsonTokenType.EndObject)
				{
					return waveGroupData;
				}
				if (reader.TokenType != JsonTokenType.PropertyName)
				{
					throw new JsonException("Expected PropertyName when reading WaveGroup");
				}
				string text = reader.GetString().ToLower();
				reader.Read();
				switch (text)
				{
				case "waves":
				case "wave":
				{
					if (reader.TokenType == JsonTokenType.StartArray)
					{
						if (!JSON.TryDeserialize<WeightedList<WeightedWaveReference>>(ref reader, out var value3))
						{
							throw new JsonException("Expected list of wave data when reading WaveGroup");
						}
						waveGroupData.Waves = value3;
						break;
					}
					if (!JSON.TryDeserialize<WeightedWaveReference>(ref reader, out var value4))
					{
						throw new JsonException("Expected wave data when reading WaveGroup");
					}
					waveGroupData.Waves = new WeightedList<WeightedWaveReference> { value4 };
					break;
				}
				case "eventdata":
				case "events":
				case "event":
				{
					if (reader.TokenType == JsonTokenType.StartArray)
					{
						if (!JSON.TryDeserialize<List<JsonReference<WaveEventData>>>(ref reader, out var value))
						{
							throw new JsonException("Expected list of event data when reading WaveGroup");
						}
						waveGroupData.Events = value;
						break;
					}
					if (!JSON.TryDeserialize<JsonReference<WaveEventData>>(ref reader, out var value2))
					{
						throw new JsonException("Expected wave data when reading WaveGroup");
					}
					waveGroupData.Events = new List<JsonReference<WaveEventData>> { value2 };
					break;
				}
				}
			}
			throw new JsonException("Expected EndObject when reading WaveGroup");
		}

		public override void Write(Utf8JsonWriter writer, WaveGroupData? value, JsonSerializerOptions options)
		{
			if (value == null)
			{
				writer.WriteNullValue();
				return;
			}
			writer.WriteStartObject();
			writer.WritePropertyName("Wave");
			if (value.Waves.Count == 1)
			{
				JsonSerializer.Serialize(writer, value.Waves[0], options);
			}
			else
			{
				JsonSerializer.Serialize(writer, value.Waves, options);
			}
			writer.WritePropertyName("Event");
			if (value.Events.Count == 1)
			{
				JsonSerializer.Serialize(writer, value.Events[0], options);
			}
			else
			{
				JsonSerializer.Serialize(writer, value.Events, options);
			}
			writer.WriteEndObject();
		}
	}
	public sealed class WeightedEnemyConverter : JsonConverter<WeightedEnemyData>
	{
		public override WeightedEnemyData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			using JsonDocument jsonDocument = JsonDocument.ParseValue(ref reader);
			JsonElement rootElement = jsonDocument.RootElement;
			WeightedEnemyData weightedEnemyData = new WeightedEnemyData();
			if (rootElement.ValueKind == JsonValueKind.Number)
			{
				weightedEnemyData.ID = rootElement.GetUInt32();
				return weightedEnemyData;
			}
			if (rootElement.ValueKind != JsonValueKind.Array)
			{
				throw new JsonException("Expected enemy data to be either a number or list");
			}
			JsonElement.ArrayEnumerator arrayEnumerator = rootElement.EnumerateArray();
			if (arrayEnumerator.MoveNext())
			{
				weightedEnemyData.ID = arrayEnumerator.Current.GetUInt32();
			}
			if (arrayEnumerator.MoveNext())
			{
				weightedEnemyData.Weight = arrayEnumerator.Current.GetSingle();
			}
			if (arrayEnumerator.MoveNext())
			{
				weightedEnemyData.Cost = arrayEnumerator.Current.GetInt32();
			}
			if (arrayEnumerator.MoveNext())
			{
				throw new JsonException("Expected weighted enemy tuple to be at most 3 elements long");
			}
			return weightedEnemyData;
		}

		public override void Write(Utf8JsonWriter writer, WeightedEnemyData? value, JsonSerializerOptions options)
		{
			if (value == null)
			{
				writer.WriteNullValue();
				return;
			}
			if (value.Weight == 1f && value.Cost == 1)
			{
				writer.WriteNumberValue(value.ID);
				return;
			}
			writer.WriteStartArray();
			writer.WriteNumberValue(value.ID);
			writer.WriteNumberValue(value.Weight);
			writer.WriteNumberValue(value.Cost);
			writer.WriteEndArray();
		}
	}
	public sealed class WeightedWaveConverter : JsonConverter<WeightedWaveReference>
	{
		public override WeightedWaveReference? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			using JsonDocument jsonDocument = JsonDocument.ParseValue(ref reader);
			JsonElement rootElement = jsonDocument.RootElement;
			WeightedWaveReference weightedWaveReference = new WeightedWaveReference();
			if (rootElement.ValueKind == JsonValueKind.String || rootElement.ValueKind == JsonValueKind.Object)
			{
				DeserializeReference(rootElement, weightedWaveReference, options);
				return weightedWaveReference;
			}
			if (rootElement.ValueKind != JsonValueKind.Array)
			{
				throw new JsonException("Expected wave data or list of weighted waves");
			}
			JsonElement.ArrayEnumerator arrayEnumerator = rootElement.EnumerateArray();
			if (arrayEnumerator.MoveNext())
			{
				DeserializeReference(arrayEnumerator.Current, weightedWaveReference, options);
			}
			if (arrayEnumerator.MoveNext())
			{
				weightedWaveReference.Weight = arrayEnumerator.Current.GetSingle();
			}
			if (arrayEnumerator.MoveNext())
			{
				throw new JsonException("Expected weighted wave data to be 2 elements long");
			}
			return weightedWaveReference;
		}

		private static void DeserializeReference(JsonElement element, WeightedWaveReference data, JsonSerializerOptions options)
		{
			switch (element.ValueKind)
			{
			case JsonValueKind.Null:
				break;
			case JsonValueKind.String:
				data.ID = element.Deserialize<string>(options);
				break;
			default:
				data.Value = element.Deserialize<WaveData>(options);
				break;
			}
		}

		public override void Write(Utf8JsonWriter writer, WeightedWaveReference? value, JsonSerializerOptions options)
		{
			if (value == null)
			{
				writer.WriteNullValue();
				return;
			}
			if (value.Value != null)
			{
				JsonSerializer.Serialize(writer, value.Value, options);
				return;
			}
			if (value.Weight == 1f)
			{
				JsonSerializer.Serialize(writer, (JsonReference<WaveData>)value, options);
				return;
			}
			writer.WriteStartArray();
			JsonSerializer.Serialize(writer, (JsonReference<WaveData>)value, options);
			writer.WriteNumberValue(value.Weight);
			writer.WriteEndArray();
		}
	}
}
namespace WaveSurvival.Json.Converters.Utils
{
	public class LocaleTextConverter : JsonConverter<LocaleText>
	{
		public override bool HandleNull => true;

		public override LocaleText Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			return reader.TokenType switch
			{
				JsonTokenType.String => new LocaleText(reader.GetString()), 
				JsonTokenType.Number => new LocaleText(reader.GetUInt32()), 
				JsonTokenType.Null => LocaleText.Empty, 
				_ => throw new JsonException($"LocaleTextJson type: {reader.TokenType} is not implemented!"), 
			};
		}

		public override void Write(Utf8JsonWriter writer, LocaleText value, JsonSerializerOptions options)
		{
			if (value.ID != 0)
			{
				writer.WriteNumberValue(value.ID);
			}
			else
			{
				writer.WriteStringValue(value.RawText);
			}
		}
	}
	public sealed class OptionalListConverter<T> : JsonConverter<List<T>>
	{
		public override List<T>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			List<T> list = new List<T>();
			if (reader.TokenType == JsonTokenType.StartArray)
			{
				while (reader.Read())
				{
					if (reader.TokenType == JsonTokenType.EndArray)
					{
						return list;
					}
					list.Add(JsonSerializer.Deserialize<T>(ref reader, options));
				}
				throw new JsonException("Expected EndArray when reading list");
			}
			list.Add(JsonSerializer.Deserialize<T>(ref reader, options));
			return list;
		}

		public override void Write(Utf8JsonWriter writer, List<T>? value, JsonSerializerOptions options)
		{
			if (value == null)
			{
				writer.WriteNullValue();
				return;
			}
			if (value.Count == 1)
			{
				JsonSerializer.Serialize(writer, value[0], options);
				return;
			}
			writer.WriteStartArray();
			foreach (T item in value)
			{
				JsonSerializer.Serialize(writer, item, options);
			}
			writer.WriteEndArray();
		}
	}
	public sealed class WeightedListConverterFactory : JsonConverterFactory
	{
		public override bool CanConvert(Type typeToConvert)
		{
			if (!typeToConvert.IsGenericType)
			{
				return false;
			}
			return typeToConvert.GetGenericTypeDefinition() == typeof(WeightedList<>);
		}

		public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
		{
			Type type = typeToConvert.GetGenericArguments()[0];
			return (JsonConverter)Activator.CreateInstance(typeof(WeightedListConverter<>).MakeGenericType(type));
		}
	}
	public sealed class WeightedListConverter<T> : JsonConverter<WeightedList<T>> where T : IWeightable
	{
		public override WeightedList<T>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
		{
			return JsonSerializer.Deserialize<List<T>>(ref reader, options);
		}

		public override void Write(Utf8JsonWriter writer, WeightedList<T>? value, JsonSerializerOptions options)
		{
			if (value == null)
			{
				writer.WriteNullValue();
			}
			else
			{
				JsonSerializer.Serialize(writer, value.Values, options);
			}
		}
	}
}
namespace WaveSurvival.Dependencies
{
	internal static class MTFOWrapper
	{
		public const string PLUGIN_GUID = "com.dak.MTFO";
	}
	internal static class PartialData
	{
		public const string PLUGIN_GUID = "MTFO.Extension.PartialBlocks";

		public static readonly bool HasPData;

		static PartialData()
		{
			HasPData = ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.ContainsKey("MTFO.Extension.PartialBlocks");
		}

		public static bool TryGetGUID(string text, out uint guid)
		{
			if (!HasPData)
			{
				guid = 0u;
				return false;
			}
			return TryGetGUID_Internal(text, out guid);
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool TryGetGUID_Internal(string text, out uint guid)
		{
			return PersistentIDManager.TryGetId(text, ref guid);
		}
	}
}
namespace WaveSurvival.CustomWave
{
	public sealed class ActiveWave
	{
		private class SpawnSet
		{
			protected Queue<(uint id, int cost)> _spawnQueue = new Queue<(uint, int)>();

			public readonly SpawnData Settings;

			public int RemainingEnemies => _spawnQueue.Count;

			public bool IsDone => _spawnQueue.Count == 0;

			public SpawnSet(SpawnData data)
			{
				Settings = data;
				if (Settings.Count > 0)
				{
					SetupWeightedSpawns();
				}
				else
				{
					SetupUnweightedSpawns();
				}
			}

			public (uint id, int cost) Dequeue()
			{
				return _spawnQueue.Dequeue();
			}

			private void SetupUnweightedSpawns()
			{
				foreach (WeightedEnemyData item in (List<WeightedEnemyData>)Settings.Enemies)
				{
					_spawnQueue.Enqueue((item.ID, 1));
				}
			}

			private void SetupWeightedSpawns()
			{
				List<WeightedEnemyData> list = Settings.Enemies;
				float num = list.Sum((WeightedEnemyData data) => data.Weight);
				int num2 = Settings.Count;
				while (num2 > 0)
				{
					float num3 = WaveManager.Random.NextSingle(num);
					float num4 = 0f;
					foreach (WeightedEnemyData item in list)
					{
						if (item.Cost > num2)
						{
							if (num != num4)
							{
								num = num4;
								break;
							}
							DinoLogger.Warning($"Wave spawn unable to use {num2} remaining count (total count: {Settings.Count}, costs: [{string.Join(",", list.ConvertAll((WeightedEnemyData e) => e.Cost))}])!");
							num2 = 0;
							break;
						}
						num4 += item.Weight;
						if (num3 < num4 && num2 >= item.Cost)
						{
							_spawnQueue.Enqueue((item.ID, item.Cost));
							num2 -= item.Cost;
							break;
						}
					}
				}
			}
		}

		[CompilerGenerated]
		private sealed class <DoSpawns>d__23 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public ActiveWave <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DoSpawns>d__23(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				ActiveWave activeWave = <>4__this;
				SpawnData settings;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					goto IL_0108;
				case 1:
					<>1__state = -1;
					goto IL_0045;
				case 2:
					{
						<>1__state = -1;
						goto IL_00fa;
					}
					IL_0108:
					if (activeWave.IsDone)
					{
						return false;
					}
					goto IL_0045;
					IL_0045:
					if (!activeWave.CanDoSpawn())
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					activeWave._lastSubWaveTime = Clock.Time;
					settings = activeWave._currentSpawn.Settings;
					if (WaveManager.Random.NextSingle() < settings.RandomDirectionChance)
					{
						WaveManager.Current.SetRandomSpawner(ref activeWave._spawner);
					}
					foreach (WardenObjectiveEventData item in settings.EventsOnSubWaveStart)
					{
						WardenObjectiveManager.CheckAndExecuteEventsOnTrigger(item, (eWardenObjectiveEventTrigger)0, true, 0f);
					}
					WaveNetwork.DoWaveScream(settings.SubWaveScreamSize, settings.SubWaveScreamType, activeWave._spawner.Node.Position);
					goto IL_00fa;
					IL_00fa:
					if (activeWave.TryAddSpawns())
					{
						<>2__current = null;
						<>1__state = 2;
						return true;
					}
					activeWave.IncrementSpawn();
					goto IL_0108;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <SpawnWave>d__22 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public ActiveWave <>4__this;

			private IEnumerator <spawns>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SpawnWave>d__22(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<spawns>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				ActiveWave activeWave = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					activeWave._lastSubWaveTime = Clock.Time;
					<spawns>5__2 = activeWave.DoSpawns();
					goto IL_0059;
				case 1:
					<>1__state = -1;
					goto IL_0059;
				case 2:
					{
						<>1__state = -1;
						break;
					}
					IL_0059:
					if (<spawns>5__2.MoveNext())
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					break;
				}
				if (activeWave.EnemyCount != 0 || activeWave.QueuedCount != 0)
				{
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public readonly WaveData Settings;

		public readonly WaveEventData EventData;

		private readonly IEnumerator _update;

		private readonly Queue<SpawnSet> _spawnSetQueue;

		private SpawnSet? _currentSpawn;

		private float _lastSubWaveTime;

		private float _nextIntervalTime;

		private int _intervalCount;

		private EnemySpawner _spawner;

		public int EnemyCount { get; private set; }

		public int QueuedCount { get; private set; }

		[MemberNotNullWhen(false, "_currentSpawn")]
		private bool IsDone
		{
			[MemberNotNullWhen(false, "_currentSpawn")]
			get
			{
				return _currentSpawn == null;
			}
		}

		public ActiveWave(WaveData settings, WaveEventData eventData)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			Settings = settings;
			EventData = eventData;
			_update = SpawnWave();
			_spawnSetQueue = new Queue<SpawnSet>();
			SetupSpawns();
			WaveManager.Current.SetRandomSpawner(ref _spawner);
			WaveNetwork.DoWaveScream(Settings.ScreamSize, Settings.ScreamType, _spawner.Node.Position);
		}

		private void SetupSpawns()
		{
			int num = 0;
			foreach (JsonReference<SpawnData> spawn in Settings.Spawns)
			{
				SpawnData spawnData = spawn;
				SpawnSet spawnSet = new SpawnSet(spawnData);
				_spawnSetQueue.Enqueue(spawnSet);
				if (!spawnData.HideFromTotalCount)
				{
					num += spawnSet.RemainingEnemies;
				}
			}
			if (!_spawnSetQueue.TryDequeue(out _currentSpawn))
			{
				_currentSpawn = null;
			}
			WaveManager.Current.AddWaveEnemyCount(num);
		}

		public bool UpdateCheckDone()
		{
			if (_update.MoveNext())
			{
				return false;
			}
			return true;
		}

		public void OnEnemySpawned(bool hideFromCount)
		{
			EnemyCount++;
			QueuedCount--;
			WaveManager.Current.OnEnemySpawned(hideFromCount);
		}

		public void OnEnemyDead()
		{
			EnemyCount--;
			WaveManager.Current.OnEnemyDead();
		}

		[IteratorStateMachine(typeof(<SpawnWave>d__22))]
		private IEnumerator SpawnWave()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SpawnWave>d__22(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<DoSpawns>d__23))]
		private IEnumerator DoSpawns()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DoSpawns>d__23(0)
			{
				<>4__this = this
			};
		}

		private bool CanDoSpawn()
		{
			if (IsDone)
			{
				return false;
			}
			SpawnData settings = _currentSpawn.Settings;
			if (settings.SubWaveMaxCount > 0 && settings.SubWaveMaxCount <= QueuedCount + EnemyCount)
			{
				return false;
			}
			if (settings.SubWaveDelay > Clock.Time - _lastSubWaveTime)
			{
				return false;
			}
			return true;
		}

		private void IncrementSpawn()
		{
			if (!_spawnSetQueue.TryDequeue(out _currentSpawn))
			{
				_currentSpawn = null;
			}
			_intervalCount = 0;
			_nextIntervalTime = 0f;
		}

		private bool TryAddSpawns()
		{
			if (_currentSpawn.IsDone)
			{
				return false;
			}
			if (Clock.Time < _nextIntervalTime)
			{
				return true;
			}
			SpawnData settings = _currentSpawn.Settings;
			var (id, num) = _currentSpawn.Dequeue();
			_spawner.AddSpawn(id, settings.SpawnRate, settings.HideFromTotalCount, this);
			QueuedCount++;
			_intervalCount += num;
			if (_intervalCount >= settings.SpawnInterval)
			{
				_nextIntervalTime = Clock.Time + settings.SpawnDelayOnInterval;
				_intervalCount -= settings.SpawnInterval;
				if (WaveManager.Random.NextSingle() < settings.RandomDirectionChanceOnInterval)
				{
					WaveManager.Current.SetRandomSpawner(ref _spawner);
				}
			}
			return !_currentSpawn.IsDone;
		}
	}
	public sealed class EnemySpawner
	{
		private static float s_lastSpawnTime;

		public readonly AIG_CourseNode Node;

		public readonly ZoneNode ZoneNode;

		public readonly int ID;

		private readonly Placement[] _spawnPositions;

		private readonly Queue<(uint id, float delay, bool isHidden, ActiveWave wave)> _queuedSpawns = new Queue<(uint, float, bool, ActiveWave)>();

		private int _useCount;

		private int _validCount;

		private int _spawnIndex;

		public bool Valid
		{
			get
			{
				return _validCount > 0;
			}
			set
			{
				_validCount += (value ? 1 : (-1));
			}
		}

		public bool Used
		{
			get
			{
				return _useCount > 0;
			}
			set
			{
				_useCount += (value ? 1 : (-1));
			}
		}

		public EnemySpawner(AIG_CourseNode node)
		{
			//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_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			Node = node;
			ZoneNode = ZoneTree.GetZoneNode(node.m_zone);
			ID = node.NodeID;
			AIG_NodeCluster nodeCluster = node.m_nodeCluster;
			_spawnPositions = (Placement[])(object)new Placement[nodeCluster.m_scoredPlacements.Count];
			for (int i = 0; i < _spawnPositions.Length; i++)
			{
				_spawnPositions[i] = new Placement(nodeCluster.m_scoredPlacements[i].item.Position, EnemyGroup.GetRandomRotation());
			}
			WaveManager.Random.Shuffle(_spawnPositions);
		}

		public bool UpdateCheckDone()
		{
			float time = Clock.Time;
			if (_queuedSpawns.TryPeek(out (uint, float, bool, ActiveWave) result) && time >= result.Item2 + s_lastSpawnTime)
			{
				_queuedSpawns.Dequeue();
				SpawnEnemy(result.Item1, result.Item3, result.Item4);
				s_lastSpawnTime = time;
			}
			if (_queuedSpawns.Count == 0 && !Valid)
			{
				return !Used;
			}
			return false;
		}

		public void AddSpawn(uint id, float spawnRate, bool hideFromCount, ActiveWave wave)
		{
			_queuedSpawns.Enqueue((id, 1f / spawnRate, hideFromCount, wave));
		}

		private void SpawnEnemy(uint id, bool hideFromCount, ActiveWave wave)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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)
			Placement val = _spawnPositions[_spawnIndex++];
			if (_spawnIndex >= _spawnPositions.Length)
			{
				WaveManager.Random.Shuffle(_spawnPositions);
				_spawnIndex = 0;
			}
			EnemyAgent agent = EnemyAllocator.Current.SpawnEnemy(id, Node, (AgentMode)1, val.position, val.rotation, (EnemyGroup)null, -1);
			wave.OnEnemySpawned(hideFromCount);
			agent.AddOnDeadOnce(wave.OnEnemyDead);
		}
	}
	public sealed class SpawnPath
	{
		private readonly List<EnemySpawner> _path;

		private int _pathIndex;

		public SpawnPath(List<EnemySpawner> pathList)
		{
			_path = pathList;
			_pathIndex = -1;
		}

		public bool TryUpdatePath(bool opened, out EnemySpawner? spawner, out EnemySpawner? oldSpawner)
		{
			if (!opened)
			{
				return TryRevertPath(out spawner, out oldSpawner);
			}
			return TryAdvancePath(out spawner, out oldSpawner);
		}

		public bool TryRevertPath(out EnemySpawner? spawner, [MaybeNullWhen(false)] out EnemySpawner oldSpawner)
		{
			if (_pathIndex == -1 || _path[_pathIndex].ZoneNode.IsReachable)
			{
				spawner = null;
				oldSpawner = null;
				return false;
			}
			int num = _pathIndex;
			while (num - 1 >= 0 && !_path[num - 1].ZoneNode.IsReachable)
			{
				num--;
			}
			oldSpawner = _path[_pathIndex];
			oldSpawner.Valid = false;
			_pathIndex = num;
			if (_pathIndex >= 0)
			{
				spawner = _path[num];
				spawner.Valid = true;
			}
			else
			{
				spawner = null;
			}
			return true;
		}

		public bool TryAdvancePath([MaybeNullWhen(false)] out EnemySpawner spawner, out EnemySpawner? oldSpawner)
		{
			int i;
			for (i = _pathIndex; i + 1 < _path.Count && _path[i + 1].ZoneNode.IsReachable; i++)
			{
			}
			if (i == _pathIndex)
			{
				oldSpawner = null;
				spawner = null;
				return false;
			}
			if (_pathIndex >= 0)
			{
				oldSpawner = _path[_pathIndex];
				oldSpawner.Valid = false;
			}
			else
			{
				oldSpawner = null;
			}
			_pathIndex = i;
			spawner = _path[i];
			spawner.Valid = true;
			return true;
		}
	}
	public sealed class WaveManager : MonoBehaviour
	{
		private struct CheckpointData
		{
			public bool active;

			public WaveObjectiveData objective;

			public List<KeyValuePair<eDimensionIndex, WaveObjectiveData>> dimensionStartData;

			public List<WaveStep> waves;

			public int currentWave;
		}

		private readonly struct WaveStep
		{
			public readonly WaveData Wave;

			public readonly WaveEventData EventData;

			public WaveStep(WaveData wave, WaveEventData eventData)
			{
				Wave = wave;
				EventData = eventData;
			}
		}

		public static readonly Random Random = new Random();

		private CheckpointData _checkpointData;

		private int _enemyCount;

		private readonly Dictionary<eDimensionIndex, WaveObjectiveData> _dimensionStartData = new Dictionary<eDimensionIndex, WaveObjectiveData>();

		private readonly Dictionary<eWardenObjectiveEventType, WaveObjectiveData> _eventStartData = new Dictionary<eWardenObjectiveEventType, WaveObjectiveData>();

		private readonly Dictionary<eWardenObjectiveEventType, WaveObjectiveData> _eventStopData = new Dictionary<eWardenObjectiveEventType, WaveObjectiveData>();

		private readonly List<SpawnPath> _spawnPaths = new List<SpawnPath>();

		private readonly Dictionary<int, EnemySpawner> _activeSpawners = new Dictionary<int, EnemySpawner>();

		private readonly Dictionary<int, EnemySpawner> _validSpawners = new Dictionary<int, EnemySpawner>();

		private readonly List<EnemySpawner> _finishedSpawners = new List<EnemySpawner>();

		private readonly List<WaveStep> _waves = new List<WaveStep>();

		private readonly Dictionary<int, ActiveWave> _activeWaves = new Dictionary<int, ActiveWave>();

		private readonly List<(int, ActiveWave)> _finishedWaves = new List<(int, ActiveWave)>();

		private float _nextWaveTime;

		private float _nextWaveDelayCache;

		private int _currentWave = -1;

		public static WaveManager Current { get; private set; } = null;


		public static bool IsActive { get; private set; } = false;


		public static bool IsMaster { get; private set; } = false;


		public static WaveObjectiveData? ActiveObjective { get; private set; } = null;


		public WaveManager(IntPtr ptr)
			: base(ptr)
		{
		}

		[InvokeOnLoad]
		private static void OnLoad()
		{
			ClassInjector.RegisterTypeInIl2Cpp<WaveManager>();
		}

		[InvokeOnAssetsLoaded]
		private static void OnAssetsLoaded()
		{
			//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_0010: Expected O, but got Unknown
			GameObject val = new GameObject("WaveSurvival_WaveManager");
			Object.DontDestroyOnLoad((Object)val);
			Current = val.AddComponent<WaveManager>();
			IsActive = false;
		}

		public static bool TryGetActiveObjective([MaybeNullWhen(false)] out WaveObjectiveData objective)
		{
			objective = ActiveObjective;
			if (IsActive)
			{
				return IsMaster;
			}
			return false;
		}

		private void Update()
		{
			if (!IsMaster || !IsActive)
			{
				WaveText.Current.Update();
				return;
			}
			UpdateWaves();
			UpdateSpawners();
			WaveText.Current.Update();
		}

		[InvokeOnEnter]
		private static void OnEnter()
		{
			IsMaster = SNet.IsMaster;
			Current.StartObjective();
		}

		private void StartObjective()
		{
			if (ActiveObjective != null && !IsActive && IsMaster)
			{
				WaveNetwork.SendObjective(ActiveObjective);
				IsActive = true;
				SetupSpawners();
				SetupWaves();
			}
		}

		private void FinishObjective()
		{
			WaveText.Current.Update();
			Cleanup();
		}

		[InvokeOnCleanup]
		private static void OnCleanup()
		{
			Current.Cleanup();
		}

		private void Cleanup()
		{
			CleanupWaves();
			CleanupSpawners();
			CleanupEnemyCount();
			ActiveObjective = null;
			IsActive = false;
		}

		internal static void Internal_ReceiveObjectiveComplete()
		{
			Current.FinishObjective();
		}

		internal static void Internal_ReceiveObjectiveID(int id)
		{
			if (DataManager.TryGetObjective(id, out WaveObjectiveData objective))
			{
				ActiveObjective = objective;
				IsActive = true;
				WaveText.Current.UpdateWaveHeader();
			}
		}

		internal static void Internal_OnReloadFile(List<WaveObjectiveData> dataList)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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)
			if ((Object)(object)Current == (Object)null)
			{
				return;
			}
			if (TryGetActiveObjective(out WaveObjectiveData objective))
			{
				foreach (WaveObjectiveData data in dataList)
				{
					if (data.Level.IsMatch(objective.Level) && data.RundownID == objective.RundownID && data.StartEvent == objective.StartEvent && data.DimensionIndex == objective.DimensionIndex)
					{
						ActiveObjective = data;
						break;
					}
				}
			}
			Current.LoadLevelObjectives();
		}

		internal static void Internal_OnCheckpointReached()
		{
			Current.OnCheckpointReached();
		}

		private void OnCheckpointReached()
		{
			_checkpointData.active = IsActive;
			if (TryGetActiveObjective(out WaveObjectiveData objective))
			{
				_checkpointData.objective = objective;
				CheckpointStoreObjectives();
				CheckpointStoreWaves();
			}
		}

		internal static void Internal_OnCheckpointReload()
		{
			Current.OnCheckpointReload();
		}

		private void OnCheckpointReload()
		{
			Current.Cleanup();
			if (IsMaster && _checkpointData.active)
			{
				ActiveObjective = _checkpointData.objective;
				WaveNetwork.SendObjective(ActiveObjective);
				IsActive = true;
				SetupSpawners();
				CheckpointReloadObjectives();
				CheckpointReloadWaves();
			}
		}

		public void AddWaveEnemyCount(int count)
		{
			WaveNetwork.SetEnemyCount(_enemyCount += count);
		}

		public void OnEnemySpawned(bool hideFromCount)
		{
			if (hideFromCount)
			{
				WaveNetwork.SetEnemyCount(++_enemyCount);
			}
		}

		public void OnEnemyDead()
		{
			WaveNetwork.SetEnemyCount(--_enemyCount);
		}

		private void CleanupEnemyCount()
		{
			_enemyCount = 0;
		}

		private void LoadLevelObjectives()
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: 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_0158: 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)
			uint num = default(uint);
			if (RundownManager.ActiveExpedition == null || !RundownManager.TryGetIdFromLocalRundownKey(RundownManager.ActiveRundownKey, ref num))
			{
				return;
			}
			pActiveExpedition activeExpeditionData = RundownManager.GetActiveExpeditionData();
			uint levelLayoutData = RundownManager.ActiveExpedition.LevelLayoutData;
			_dimensionStartData.Clear();
			_eventStartData.Clear();
			_eventStopData.Clear();
			foreach (WaveObjectiveData objectiveData in DataManager.ObjectiveDatas)
			{
				if ((objectiveData.RundownID != 0 && objectiveData.RundownID != num) || !objectiveData.Level.IsMatch(levelLayoutData, activeExpeditionData.tier, activeExpeditionData.expeditionIndex))
				{
					continue;
				}
				if ((int)objectiveData.StartEvent != 0)
				{
					if (!_eventStartData.TryAdd(objectiveData.StartEvent, objectiveData))
					{
						DinoLogger.Error($"Unable to register data with StartEvent {objectiveData.StartEvent} (already in use)");
					}
				}
				else if (!_dimensionStartData.TryAdd(objectiveData.DimensionIndex, objectiveData))
				{
					DinoLogger.Error($"Unable to register data with no start event and DimensionIndex {objectiveData.DimensionIndex} (already in use)");
				}
				if ((int)objectiveData.StopEvent != 0 && !_eventStopData.TryAdd(objectiveData.StopEvent, objectiveData))
				{
					DinoLogger.Error($"Unable to register data with StopEvent {objectiveData.StopEvent} (already in use)");
				}
			}
		}

		[InvokeOnBuildStart]
		private static void OnBuildStart()
		{
			Current.LoadLevelObjectives();
			if (Current._dimensionStartData.Remove((eDimensionIndex)0, out WaveObjectiveData value))
			{
				ActiveObjective = value;
			}
		}

		private void CheckpointStoreObjectives()
		{
			_checkpointData.dimensionStartData = new List<KeyValuePair<eDimensionIndex, WaveObjectiveData>>(_dimensionStartData);
		}

		private void CheckpointReloadObjectives()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			_dimensionStartData.Clear();
			foreach (KeyValuePair<eDimensionIndex, WaveObjectiveData> dimensionStartDatum in _checkpointData.dimensionStartData)
			{
				_dimensionStartData.Add(dimensionStartDatum.Key, dimensionStartDatum.Value);
			}
		}

		internal static void Internal_OnWarp(eDimensionIndex dimensionIndex)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (IsMaster && !IsActive && Current._dimensionStartData.Remove(dimensionIndex, out WaveObjectiveData value))
			{
				ActiveObjective = value;
				Current.StartObjective();
			}
		}

		internal static void Internal_OnWardenEvent(eWardenObjectiveEventType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if ((int)type == 0)
			{
				return;
			}
			IsMaster = SNet.IsMaster;
			if (IsMaster)
			{
				if (IsActive && Current._eventStopData.TryGetValue(type, out WaveObjectiveData value) && value.NetworkID == ActiveObjective?.NetworkID)
				{
					WaveNetwork.SetWavesFinished();
				}
				if (!IsActive && Current._eventStartData.TryGetValue(type, out value))
				{
					ActiveObjective = value;
					Current.StartObjective();
				}
			}
		}

		[HideFromIl2Cpp]
		public void SetRandomSpawner([NotNull] ref EnemySpawner? spawner)
		{
			if (spawner != null)
			{
				spawner.Used = false;
			}
			spawner = _validSpawners.Values.ToArray()[Random.Next(_validSpawners.Count)];
			spawner.Used = true;
		}

		private void UpdateSpawners()
		{
			foreach (EnemySpawner value in _activeSpawners.Values)
			{
				if (value.UpdateCheckDone())
				{
					_finishedSpawners.Add(value);
				}
			}
			foreach (EnemySpawner finishedSpawner in _finishedSpawners)
			{
				_activeSpawners.Remove(finishedSpawner.ID);
			}
			_finishedSpawners.Clear();
		}

		private void SetupSpawners()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			Dimension val = default(Dimension);
			if (!Builder.CurrentFloor.GetDimension(ActiveObjective.DimensionIndex, ref val))
			{
				DinoLogger.Error($"Unable to get dimension {ActiveObjective.DimensionIndex}, no spawners created!");
				return;
			}
			Dictionary<int, EnemySpawner> dictionary = new Dictionary<int, EnemySpawner>();
			foreach (List<SpawnPathData> spawnPath2 in ActiveObjective.SpawnPaths)
			{
				List<EnemySpawner> list = new List<EnemySpawner>(spawnPath2.Count);
				foreach (SpawnPathData item in spawnPath2)
				{
					LG_Layer layer = val.GetLayer(item.Layer);
					if (layer == null || !layer.m_zonesByLocalIndex.ContainsKey(item.ZoneIndex))
					{
						DinoLogger.Error($"Unable to get zone for index {item.ZoneIndex}, layer {item.Layer}!");
						continue;
					}
					LG_Zone val2 = layer.m_zonesByLocalIndex[item.ZoneIndex];
					int num = ((item.AreaIndex >= 0) ? item.AreaIndex : (val2.m_areas.Count - 1));
					if (num < 0 || num >= val2.m_areas.Count)
					{
						DinoLogger.Error($"Unable to get area index {num} for zone index {item.ZoneIndex}, layer {item.Layer} (only {val2.m_areas.Count} areas exist!)");
					}
					else
					{
						AIG_CourseNode courseNode = val2.m_areas[num].m_courseNode;
						if (!dictionary.TryGetValue(courseNode.NodeID, out var value))
						{
							dictionary.Add(courseNode.NodeID, value = new EnemySpawner(courseNode));
						}
						list.Add(value);
					}
				}
				SpawnPath spawnPath = new SpawnPath(list);
				_spawnPaths.Add(spawnPath);
				if (spawnPath.TryAdvancePath(out EnemySpawner spawner, out EnemySpawner _))
				{
					AddSpawner(spawner);
				}
			}
		}

		[HideFromIl2Cpp]
		private void AddSpawner(EnemySpawner spawner)
		{
			_activeSpawners.TryAdd(spawner.ID, spawner);
			_validSpawners.TryAdd(spawner.ID, spawner);
		}

		private void CleanupSpawners()
		{
			_spawnPaths.Clear();
			_activeSpawners.Clear();
			_validSpawners.Clear();
		}

		internal static void Internal_OnZoneTreeUpdate(bool opened)
		{
			if (!IsMaster || !IsActive)
			{
				return;
			}
			foreach (SpawnPath spawnPath in Current._spawnPaths)
			{
				if (spawnPath.TryUpdatePath(opened, out EnemySpawner spawner, out EnemySpawner oldSpawner))
				{
					if (spawner != null)
					{
						Current.AddSpawner(spawner);
					}
					if (oldSpawner != null && !oldSpawner.Valid)
					{
						Current._validSpawners.Remove(oldSpawner.ID);
					}
				}
			}
		}

		private void UpdateWaves()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if ((_nextWaveTime > 0f && Clock.Time >= _nextWaveTime) || (_activeWaves.Count == 0 && Input.GetKeyDown(Configuration.SkipWaveBind)))
			{
				StartNextWave();
			}
			foreach (var (item, activeWave2) in _activeWaves)
			{
				if (activeWave2.UpdateCheckDone())
				{
					_finishedWaves.Add((item, activeWave2));
				}
			}
			foreach (var (index, wave) in _finishedWaves)
			{
				FinishWave(index, wave);
			}
			_finishedWaves.Clear();
		}

		private void StartNextWave()
		{
			if (_currentWave >= _waves.Count - 1)
			{
				return;
			}
			WaveStep waveStep = _waves[++_currentWave];
			WaveEventData eventData = waveStep.EventData;
			_nextWaveTime = ((eventData.TimeToNextOnStart > 0f) ? (Clock.Time + eventData.TimeToNextOnStart) : 0f);
			WaveNetwork.SetWave(_currentWave, waveStep.Wave.NetworkID, _nextWaveTime, WaveState.Wave);
			foreach (WardenObjectiveEventData item in eventData.EventsOnWaveStart)
			{
				WardenObjectiveManager.CheckAndExecuteEventsOnTrigger(item, (eWardenObjectiveEventTrigger)0, true, 0f);
			}
			_activeWaves.Add(_currentWave, new ActiveWave(waveStep.Wave, eventData));
		}

		[HideFromIl2Cpp]
		private void FinishWave(int index, ActiveWave wave)
		{
			WaveEventData eventData = wave.EventData;
			bool flag = _finishedWaves.Count == _activeWaves.Count;
			if (eventData.EndOnAllWavesEnd && !flag)
			{
				return;
			}
			if (_currentWave == index)
			{
				_nextWaveDelayCache = eventData.TimeToNextOnEnd;
				if (!flag)
				{
					WaveNetwork.SetWave(_currentWave + 1, GetNetworkID(_currentWave + 1), _nextWaveTime, WaveState.RemainingWaves);
				}
			}
			foreach (WardenObjectiveEventData item in eventData.EventsOnWaveEnd)
			{
				WardenObjectiveManager.CheckAndExecuteEventsOnTrigger(item, (eWardenObjectiveEventTrigger)0, true, 0f);
			}
			if (eventData.HasAnyGain)
			{
				Enumerator<PlayerAgent> enumerator2 = PlayerManager.PlayerAgentsInLevel.GetEnumerator();
				while (enumerator2.MoveNext())
				{
					PlayerAgent current = enumerator2.Current;
					if (eventData.HasAnyAmmoGain)
					{
						PlayerBackpackManager.GiveAmmoToPlayer(current.Owner, eventData.MainAmmoGainOnEnd, eventData.SpecialAmmoGainOnEnd, eventData.ToolAmmoGainOnEnd);
					}
					if (eventData.HealthGainOnEnd > 0f)
					{
						current.GiveHealth(current, eventData.HealthGainOnEnd);
					}
				}
			}
			_activeWaves.Remove(index);
			if (flag)
			{
				float num = ((_nextWaveDelayCache > 0f) ? (Clock.Time + _nextWaveDelayCache) : 0f);
				if (_nextWaveTime == 0f)
				{
					_nextWaveTime = num;
				}
				else
				{
					_nextWaveTime = Math.Min(_nextWaveTime, num);
				}
				if (_currentWave + 1 == _waves.Count)
				{
					WaveNetwork.SetWavesFinished();
				}
				else
				{
					WaveNetwork.SetWave(_currentWave + 1, GetNetworkID(_currentWave + 1), _nextWaveTime, WaveState.Transition);
				}
			}
		}

		private int GetNetworkID(int wave)
		{
			if (wave >= _waves.Count)
			{
				return -1;
			}
			return _waves[wave].Wave.NetworkID;
		}

		private void SetupWaves()
		{
			foreach (WaveGroupData item in ActiveObjective.WaveSequence)
			{
				item.RefillWaves();
				int num = 0;
				while (num < item.Events.Count)
				{
					_waves.Add(new WaveStep(item.GetWaveData(), item.Events[num++]));
				}
			}
			_nextWaveTime = Clock.Time + ActiveObjective.StartDelay;
			_currentWave = ActiveObjective.StartWave - 2;
			WaveNetwork.SetWave(_currentWave + 1, GetNetworkID(_currentWave + 1), _nextWaveTime, WaveState.Transition);
		}

		private void CleanupWaves()
		{
			_waves.Clear();
			_activeWaves.Clear();
			_nextWaveTime = 0f;
			_nextWaveDelayCache = 0f;
			_currentWave = -1;
		}

		private void CheckpointStoreWaves()
		{
			_checkpointData.waves = new List<WaveStep>(_waves);
			_checkpointData.currentWave = ((_activeWaves.Count == 0) ? (_currentWave + 1) : _currentWave);
		}

		private void CheckpointReloadWaves()
		{
			_waves.AddRange(_checkpointData.waves);
			_currentWave = _checkpointData.currentWave - 1;
			float num = ((_currentWave > 0) ? _waves[_currentWave - 1].EventData.TimeToNextOnEnd : _checkpointData.objective.StartDelay);
			_nextWaveTime = ((num > 0f) ? (Clock.Time + num) : 0f);
			WaveNetwork.SetWave(_currentWave + 1, GetNetworkID(_currentWave + 1), _nextWaveTime, WaveState.Transition);
		}
	}
	internal static class WaveNetwork
	{
		private class ObjectiveSync : SyncedEvent<int>
		{
			public override string GUID => "Objective";

			protected override void Receive(int id)
			{
				WaveManager.Internal_ReceiveObjectiveID(id);
			}
		}

		private class WaveSync : SyncedEvent<pWaveData>
		{
			public override string GUID => "Wave";

			protected override void Receive(pWaveData packet)
			{
				WaveText.Current.Internal_ReceiveWave(packet.wave, packet.networkID, packet.nextWaveTime, packet.state);
				if (packet.state == WaveState.Finished)
				{
					WaveManager.Internal_ReceiveObjectiveComplete();
				}
			}

			protected override void ReceiveLocal(pWaveData packet)
			{
				Receive(packet);
			}
		}

		private class WaveScreamSync : SyncedEvent<pScreamData>
		{
			public override string GUID => "Scream";

			protected override void Receive(pScreamData packet)
			{
				//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: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0054: Expected O, but got Unknown
				CellSoundPlayer val = new CellSoundPlayer();
				val.SetSwitch(ENEMY_TYPE.GROUP, packet.screamType.ToSwitch());
				val.SetSwitch(ROAR_SIZE.GROUP, packet.screamSize.ToSwitch());
				val.SetSwitch(ENVIROMENT.GROUP, SWITCH.COMPLEX);
				CellSoundPlayerExt.PostWithCleanup(val, EVENTS.PLAY_WAVE_DISTANT_ROAR, packet.position);
			}

			protected override void ReceiveLocal(pScreamData packet)
			{
				Receive(packet);
			}
		}

		private class EnemyCountSync : SyncedEvent<int>
		{
			public override string GUID => "Count";

			protected override void Receive(int count)
			{
				WaveText.Current.Internal_ReceiveEnemyCount(count);
			}

			protected override void ReceiveLocal(int count)
			{
				Receive(count);
			}
		}

		private struct pWaveData
		{
			public int wave;

			public int networkID;

			public float nextWaveTime;

			public WaveState state;
		}

		private struct pScreamData
		{
			public ScreamSize screamSize;

			public ScreamType screamType;

			public Vector3 position;
		}

		private static readonly WaveSync _waveSync = new WaveSync();

		private static readonly ObjectiveSync _objectiveSync = new ObjectiveSync();

		private static readonly WaveScreamSync _waveScreamSync = new WaveScreamSync();

		private static readonly EnemyCountSync _enemyCountSync = new EnemyCountSync();

		internal static void SendObjective(WaveObjectiveData data, SNet_Player? player = null)
		{
			_objectiveSync.Send(data.NetworkID, player, (SNet_ChannelType)3);
		}

		internal static void SetWavesFinished()
		{
			SetWave(0, 0, 0f, WaveState.Finished);
		}

		internal static void SetWave(int wave, int networkID, float nextWaveTime, WaveState waveStep)
		{
			_waveSync.Send(new pWaveData
			{
				wave = wave,
				networkID = networkID,
				nextWaveTime = nextWaveTime,
				state = waveStep
			}, null, (SNet_ChannelType)3);
		}

		internal static void SetEnemyCount(int enemyCount)
		{
			_enemyCountSync.Send(enemyCount, null, (SNet_ChannelType)4);
		}

		internal static void DoWaveScream(ScreamSize screamSize, ScreamType screamType, Vector3 position)
		{
			//IL_0025: 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)
			if (screamType != ScreamType.None)
			{
				_waveScreamSync.Send(new pScreamData
				{
					screamSize = screamSize,
					screamType = screamType,
					position = position
				}, null, (SNet_ChannelType)3);
			}
		}

		[InvokeOnLoad]
		private static void OnLoad()
		{
			_waveSync.Setup();
			_objectiveSync.Setup();
			_waveScreamSync.Setup();
			_enemyCountSync.Setup();
		}
	}
	public enum WaveState : byte
	{
		Wave,
		RemainingWaves,
		Transition,
		Finished
	}
	public sealed class WaveText
	{
		public static readonly WaveText Current = new WaveText();

		private const float HideFinishDelay = 10f;

		private static PUI_ObjectiveTimer s_waveInfo = null;

		private static PUI_InteractionPrompt s_intPrompt = null;

		private static Vector2 s_IntPromptPos;

		private static Vector2 s_IntPromptPosInWave;

		private float _nextWaveTime = -1f;

		private bool _canSkip;

		private (int wave, int networkID, WaveState state) _waveCache;

		private float _hideFinishTime;

		private int _enemyCount;

		internal static void Internal_Setup(PUI_ObjectiveTimer waveInfo, PUI_InteractionPrompt intPrompt)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: 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)
			s_waveInfo = waveInfo;
			((GuiLayerComp)waveInfo).SetVisible(false, false);
			s_intPrompt = intPrompt;
			((RectTransformComp)s_intPrompt).SetVisible(false);
			s_intPrompt.SetTimerFill(0f);
			s_intPrompt.SetMessage("");
			s_intPrompt.m_timerAlpha = 0f;
			s_IntPromptPos = ((RectTransformComp)s_intPrompt).RectTrans.anchoredPosition;
			s_IntPromptPosInWave = s_IntPromptPos;
			s_IntPromptPosInWave.y -= 25f;
		}

		[InvokeOnCleanup]
		private static void OnCleanup()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			((GuiLayerComp)s_waveInfo).SetVisible(false, false);
			((RectTransformComp)s_intPrompt).SetVisible(false);
			s_intPrompt.SetMessage("");
			s_intPrompt.SetTimerFill(0f);
			s_intPrompt.m_timerAlpha = 0f;
			((RectTransformComp)s_intPrompt).RectTrans.anchoredPosition = s_IntPromptPos;
		}

		internal void Internal_ReceiveWave(int wave, int networkID, float nextWaveTime, WaveState state)
		{
			_waveCache = (wave, networkID, state);
			((GuiLayerComp)s_waveInfo).SetVisible(true, false);
			((RectTransformComp)s_intPrompt).SetVisible(state == WaveState.Wave || state == WaveState.RemainingWaves);
			_nextWaveTime = nextWaveTime;
			_canSkip = state == WaveState.Transition;
			UpdateWaveHeader();
		}

		internal void Internal_ReceiveEnemyCount(int count)
		{
			if (_enemyCount != count)
			{
				s_intPrompt.SetMessage($"Enemies Remaining: <color=orange>{count}</color>");
			}
			_enemyCount = count;
		}

		public void UpdateWaveHeader()
		{
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			if (WaveManager.ActiveObjective == null)
			{
				return;
			}
			if (_waveCache.state == WaveState.Finished)
			{
				((TMP_Text)s_waveInfo.m_titleText).SetText((string)WaveManager.ActiveObjective.CompleteHeader, true);
				_nextWaveTime = 0f;
				if (_hideFinishTime <= 0f)
				{
					_hideFinishTime = Clock.Time + 10f;
				}
				return;
			}
			_hideFinishTime = 0f;
			if (DataManager.TryGetWave(_waveCache.networkID, out WaveData wave))
			{
				if (_waveCache.state != 0)
				{
					((TMP_Text)s_waveInfo.m_titleText).SetText("<u>Next Wave</u><color=orange>\n{0:0}</color>", (float)(_waveCache.wave + 1));
					((RectTransformComp)s_intPrompt).RectTrans.anchoredPosition = s_IntPromptPos;
				}
				else
				{
					string text = wave.WaveHeader.ToString().Replace("[WAVE]", (_waveCache.wave + 1).ToString());
					((TMP_Text)s_waveInfo.m_titleText).SetText(text, true);
					((RectTransformComp)s_intPrompt).RectTrans.anchoredPosition = s_IntPromptPosInWave;
				}
			}
		}

		public void Update()
		{
			float time = Clock.Time;
			if (_hideFinishTime > 0f && time > _hideFinishTime)
			{
				OnCleanup();
				_hideFinishTime = 0f;
			}
			if (_nextWaveTime > 0f)
			{
				((Behaviour)s_waveInfo.m_timerText).enabled = true;
				TimeSpan timeSpan = TimeSpan.FromSeconds(_nextWaveTime - time);
				if (_canSkip)
				{
					((TMP_Text)s_waveInfo.m_timerText).SetText("<size=100%>\nNext Wave In: <color=orange>{0:00}:{1:00}</color></size>\n<color=green><size=60%>[Press 'X' to skip to next wave]</size></color>", (float)timeSpan.Minutes, (float)timeSpan.Seconds);
				}
				else
				{
					((TMP_Text)s_waveInfo.m_timerText).SetText("<size=100%>\nNext Wave In: <color=orange>{0:00}:{1:00}</color></size>", (float)timeSpan.Minutes, (float)timeSpan.Seconds);
				}
			}
			else if (_canSkip)
			{
				((Behaviour)s_waveInfo.m_timerText).enabled = true;
				((TMP_Text)s_waveInfo.m_timerText).SetText("<color=green><size=60%>[Press 'X' to skip to next wave]</size></color>", true);
			}
			else
			{
				((Behaviour)s_waveInfo.m_timerText).enabled = false;
			}
		}
	}
	public sealed class ZoneNode
	{
		public readonly LG_Zone Zone;

		public readonly ZoneNode? Parent;

		public readonly List<ZoneNode> Children = new List<ZoneNode>();

		public bool IsOpened { get; private set; }

		public bool IsReachable { get; private set; }

		public ZoneNode(LG_Zone zone)
		{
			Zone = zone;
			LG_Gate sourceGate = zone.m_sourceGate;
			object obj;
			if (sourceGate == null)
			{
				obj = null;
			}
			else
			{
				LG_Area linksFrom = ((LG_ZoneExpander)sourceGate).m_linksFrom;
				obj = ((linksFrom != null) ? linksFrom.m_zone : null);
			}
			LG_Zone val = (LG_Zone)obj;
			if ((Object)(object)val != (Object)null)
			{
				Parent = ZoneTree.GetZoneNode(val);
				Parent.Children.Add(this);
				IsOpened = zone.m_sourceGate.IsTraversable;
			}
			else
			{
				IsOpened = true;
			}
		}

		public void SetOpenAndPropagate(bool opened)
		{
			IsOpened = opened;
			PropagateReachable(Parent?.IsReachable ?? true);
		}

		private void PropagateReachable(bool reachable)
		{
			reachable &= IsOpened;
			if (IsReachable != reachable)
			{
				foreach (ZoneNode child in Children)
				{
					child.PropagateReachable(reachable);
				}
			}
			IsReachable = reachable;
		}
	}
	public sealed class ZoneTree
	{
		public static readonly ZoneTree Current = new ZoneTree();

		private readonly Dictionary<int, ZoneNode> _zoneToNode = new Dictionary<int, ZoneNode>();

		public static bool IsReady { get; private set; } = false;


		public static ZoneNode GetZoneNode(LG_Zone zone)
		{
			return Current._zoneToNode[zone.ID];
		}

		[InvokeOnBuildDone]
		private static void OnBuildDone()
		{
			Current.BuildZoneTree();
		}

		private void BuildZoneTree()
		{
			Enumerator<LG_Zone> enumerator = Builder.CurrentFloor.allZones.GetEnumerator();
			while (enumerator.MoveNext())
			{
				LG_Zone current = enumerator.Current;
				_zoneToNode.Add(current.ID, new ZoneNode(current));
			}
			Enumerator<Dimension> enumerator2 = Builder.CurrentFloor.m_dimensions.GetEnumerator();
			while (enumerator2.MoveNext())
			{
				List<LG_Zone> zones = enumerator2.Current.MainLayer.m_zones;
				if (zones.Count > 0)
				{
					_zoneToNode[zones[0].ID].SetOpenAndPropagate(opened: true);
				}
			}
			IsReady = true;
		}

		[InvokeOnCleanup]
		private static void OnCleanup()
		{
			Current._zoneToNode.Clear();
			IsReady = false;
		}

		internal static void Internal_OnDoorStateChanged(LG_Gate gate, bool opened)
		{
			if (IsReady)
			{
				GetZoneNode(((LG_ZoneExpander)gate).m_linksTo.m_zone).SetOpenAndPropagate(opened);
				WaveManager.Internal_OnZoneTreeUpdate(opened);
			}
		}
	}
}
namespace WaveSurvival.CustomWaveData
{
	public sealed class DataManager
	{
		private class DataFolder<T> where T : new()
		{
			public readonly string Dir;

			private readonly Dictionary<string, Dictionary<string, T>> _fileData = new Dictionary<string, Dictionary<string, T>>();

			private readonly Dictionary<string, T> _idMap = new Dictionary<string, T>();

			public DataFolder(string dir)
			{
				Dir = dir;
			}

			public bool TryGetValue(string id, [MaybeNullWhen(false)] out T value)
			{
				return _idMap.TryGetValue(id, out value);
			}

			public void SetFileData(string filepath, Dictionary<string, T> data)
			{
				_fileData[filepath] = data;
			}

			public void RemoveFile(string filepath)
			{
				_fileData.Remove(filepath);
			}

			public void ReloadIDs(Action<T>? onAddData = null)
			{
				_idMap.Clear();
				foreach (KeyValuePair<string, Dictionary<string, T>> item in _fileData.OrderBy<KeyValuePair<string, Dictionary<string, T>>, string>((KeyValuePair<string, Dictionary<string, T>> kv) => kv.Key, StringComparer.Ordinal))
				{
					item.Deconstruct(out var key, out var value);
					foreach (KeyValuePair<string, T> item2 in value)
					{
						item2.Deconstruct(out key, out var value2);
						string text = key;
						T val = value2;
						if (!_idMap.TryAdd(text, val))
						{
							DinoLogger.Error($"Found duplicate id {text} in {Dir}, skipping...");
						}
						else
						{
							onAddData?.Invoke(val);
						}
					}
				}
			}
		}

		public static readonly DataManager Current = new DataManager();

		private const string ObjectiveDir = "Main";

		private const string DataDir = "Data";

		private readonly DataFolder<WaveData> _waveFolder = new DataFolder<WaveData>("Waves");

		private readonly DataFolder<SpawnData> _spawnFolder = new DataFolder<SpawnData>("Spawns");

		private readonly DataFolder<List<WeightedEnemyData>> _enemyFolder = new DataFolder<List<WeightedEnemyData>>("Enemies");

		private readonly DataFolder<WaveEventData> _eventFolder = new DataFolder<WaveEventData>("Events");

		private readonly Dictionary<string, List<WaveObjectiveData>> _objectiveFiles = new Dictionary<string, List<WaveObjectiveData>>();

		private readonly List<WaveObjectiveData> _objectiveDatas = new List<WaveObjectiveData>();

		private readonly List<WaveData> _waveDatas = new List<WaveData>();

		public static IReadOnlyList<WaveObjectiveData> ObjectiveDatas => Current._objectiveDatas;

		public static IReadOnlyList<WaveData> WaveDatas => Current._waveDatas;

		private static bool Resolve<T>(JsonReference<T> reference, DataFolder<T> dataFolder) where T : new()
		{
			if (reference.Value != null)
			{
				return true;
			}
			if (dataFolder.TryGetValue(reference.ID, out T value))
			{
				reference.Value = value;
				return true;
			}
			DinoLogger.Error($"Unable to resolve ID {reference.ID} for type {typeof(T)}");
			return false;
		}

		public static bool Resolve(JsonReference<List<WeightedEnemyData>> reference)
		{
			return Resolve(reference, Current._enemyFolder);
		}

		public static bool Resolve(JsonReference<SpawnData> reference)
		{
			return Resolve(reference, Current._spawnFolder);
		}

		public static bool Resolve(JsonReference<WaveData> reference)
		{
			return Resolve(reference, Current._waveFolder);
		}

		public static bool Resolve(JsonReference<WaveEventData> reference)
		{
			return Resolve(reference, Current._eventFolder);
		}

		public static bool TryGetWave(int networkID, [MaybeNullWhen(false)] out WaveData wave)
		{
			if (networkID >= 0 && networkID < Current._waveDatas.Count)
			{
				wave = Current._waveDatas[networkID];
				return true;
			}
			wave = null;
			return false;
		}

		public static bool TryGetObjective(int networkID, [MaybeNullWhen(false)] out WaveObjectiveData objective)
		{
			if (networkID >= 0 && networkID < Current._objectiveDatas.Count)
			{
				objective = Current._objectiveDatas[networkID];
				return true;
			}
			objective = null;
			return false;
		}

		private void ObjectiveFileChanged(LiveEditEventArgs e)
		{
			LiveEditEventArgs e2 = e;
			DinoLogger.Warning("Main file " + e2.FileName + " changed");
			LiveEdit.TryReadFileContent(e2.FullPath, (Action<string>)delegate(string content)
			{
				ReadObjectiveContent(e2.FullPath, content);
			});
			OnReload();
		}

		private void ObjectiveFileRemoved(LiveEditEventArgs e)
		{
			DinoLogger.Warning("Main file " + e.FileName + " removed");
			_objectiveFiles.Remove(e.FullPath);
			OnReload();
		}

		private void ReadObjectiveContent(string filepath, string content)
		{
			if (!JSON.TryDeserializeSafe<List<WaveObjectiveData>>(content, out var value))
			{
				DinoLogger.Error("Failed to read main file!");
				return;
			}
			WaveManager.Internal_OnReloadFile(value);
			_objectiveFiles[filepath] = value;
		}

		private LiveEditEventHandler DataFileChanged<T>(DataFolder<T> dataFolder) where T : new()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			DataFolder<T> dataFolder2 = dataFolder;
			return (LiveEditEventHandler)delegate(LiveEditEventArgs e)
			{
				DinoLogger.Warning(dataFolder2.Dir + " file " + e.FileName + " changed");
				LiveEdit.TryReadFileContent(e.FullPath, (Action<string>)delegate(string content)
				{
					ReadDataContent(e.FullPath, content, dataFolder2);
				});
				OnReload();
			};
		}

		private LiveEditEventHandler DataFileRemoved<T>(DataFolder<T> dataFolder) where T : new()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			DataFolder<T> dataFolder2 = dataFolder;
			return (LiveEditEventHandler)delegate(LiveEditEventArgs e)
			{
				DinoLogger.Warning(dataFolder2.Dir + " file " + e.FileName + " removed");
				dataFolder2.RemoveFile(e.FullPath);
				OnReload();
			};
		}

		private void ReadDataContent<T>(string filepath, string content, DataFolder<T> dataFolder) where T : new()
		{
			if (!JSON.TryDeserializeSafe<Dictionary<string, T>>(content, out var value))
			{
				DinoLogger.Error("Failed to read " + dataFolder.Dir + " file!");
			}
			else
			{
				dataFolder.SetFileData(filepath, value);
			}
		}

		private void OnReload()
		{
			_waveDatas.Clear();
			_enemyFolder.ReloadIDs();
			_spawnFolder.ReloadIDs();
			_waveFolder.ReloadIDs(delegate(WaveData data)
			{
				data.NetworkID = _waveDatas.Count;
				_waveDatas.Add(data);
			});
			_eventFolder.ReloadIDs();
			_objectiveDatas.Clear();
			foreach (KeyValuePair<string, List<WaveObjectiveData>> item in _objectiveFiles.OrderBy<KeyValuePair<string, List<WaveObjectiveData>>, string>((KeyValuePair<string, List<WaveObjectiveData>> kv) => kv.Key, StringComparer.Ordinal))
			{
				item.Deconstruct(out var _, out var value);
				foreach (WaveObjectiveData item2 in value)
				{
					item2.NetworkID = _objectiveDatas.Count;
					_objectiveDatas.Add(item2);