Decompiled source of REPOLib v2.0.1

plugins/REPOLib.dll

Decompiled 4 days 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.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using REPOLib.Commands;
using REPOLib.Extensions;
using REPOLib.Modules;
using REPOLib.Objects;
using REPOLib.Objects.Sdk;
using REPOLib.Patches;
using TMPro;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Zehs")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2025 Zehs")]
[assembly: AssemblyDescription("Library for adding content to R.E.P.O.")]
[assembly: AssemblyFileVersion("2.0.1.0")]
[assembly: AssemblyInformationalVersion("2.0.1+56712f43ffba9641e36a63c6b573cff6e2791c96")]
[assembly: AssemblyProduct("REPOLib")]
[assembly: AssemblyTitle("REPOLib")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ZehsTeam/REPOLib")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace REPOLib
{
	public static class BundleLoader
	{
		private class LoadOperation
		{
			public enum State
			{
				LoadingBundle,
				LoadingContent
			}

			public string Path { get; }

			public DateTime StartTime { get; }

			public State CurrentState { get; set; }

			public bool LoadContents { get; }

			public Func<AssetBundle, IEnumerator>? OnBundleLoaded { get; }

			public AssetBundleCreateRequest BundleRequest { get; }

			public TimeSpan ElapsedTime => DateTime.Now - StartTime;

			public string FileName => System.IO.Path.GetFileNameWithoutExtension(Path);

			public LoadOperation(string path, Func<AssetBundle, IEnumerator>? onBundleLoaded = null, bool loadContents = true)
			{
				Path = path;
				StartTime = DateTime.Now;
				LoadContents = loadContents;
				OnBundleLoaded = onBundleLoaded;
				BundleRequest = AssetBundle.LoadFromFileAsync(path);
				base..ctor();
			}
		}

		[StructLayout(LayoutKind.Auto)]
		[CompilerGenerated]
		private struct <>c__DisplayClass11_0
		{
			public LoadOperation operation;
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass6_0
		{
			public Action<AssetBundle> onLoaded;
		}

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

			private object <>2__current;

			public LoadOperation operation;

			private <>c__DisplayClass11_0 <>8__1;

			private AssetBundle <bundle>5__2;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = default(<>c__DisplayClass11_0);
				<bundle>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1.operation = operation;
					<>2__current = <>8__1.operation.BundleRequest;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<bundle>5__2 = <>8__1.operation.BundleRequest.assetBundle;
					if ((Object)(object)<bundle>5__2 == (Object)null)
					{
						Logger.LogError("Failed to load bundle " + <>8__1.operation.FileName + "!");
						<FinishLoadOperation>g__Finish|11_0(ref <>8__1);
						return false;
					}
					if (<>8__1.operation.LoadContents)
					{
						<>2__current = LoadBundleContent(<>8__1.operation, <bundle>5__2);
						<>1__state = 2;
						return true;
					}
					goto IL_00f6;
				case 2:
					<>1__state = -1;
					goto IL_00f6;
				case 3:
					{
						<>1__state = -1;
						break;
					}
					IL_00f6:
					if (<>8__1.operation.OnBundleLoaded != null)
					{
						<>2__current = <>8__1.operation.OnBundleLoaded(<bundle>5__2);
						<>1__state = 3;
						return true;
					}
					break;
				}
				if (ConfigManager.ExtendedLogging.Value)
				{
					Logger.LogInfo($"Loaded bundle {<>8__1.operation.FileName} in {<>8__1.operation.ElapsedTime.TotalSeconds:N1}s");
				}
				<FinishLoadOperation>g__Finish|11_0(ref <>8__1);
				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();
			}
		}

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

			private object <>2__current;

			public MonoBehaviour behaviour;

			private TMP_Text <text>5__2;

			private Action <disableLoadingUI>5__3;

			private float <lastUpdate>5__4;

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

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

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

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

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					LoadOperation[] array = _operations.ToArray();
					foreach (LoadOperation operation in array)
					{
						behaviour.StartCoroutine(FinishLoadOperation(operation));
					}
					(TMP_Text, Action) tuple = SetupLoadingUI();
					<text>5__2 = tuple.Item1;
					<disableLoadingUI>5__3 = tuple.Item2;
					<lastUpdate>5__4 = Time.time;
					break;
				}
				case 2:
					<>1__state = -1;
					break;
				}
				while (_operations.Count > 0)
				{
					if (Time.time - <lastUpdate>5__4 > 1f)
					{
						<lastUpdate>5__4 = Time.time;
						string arg = ((_operations.Count == 1) ? "bundle" : "bundles");
						<text>5__2.text = $"REPOLib: Waiting for {_operations.Count} {arg} to load...";
						if (!ConfigManager.ExtendedLogging.Value)
						{
							continue;
						}
						foreach (LoadOperation operation2 in _operations)
						{
							string text = $"Loading {operation2.FileName}: {operation2.CurrentState}";
							float? num = ((operation2.CurrentState != 0) ? null : new float?(((AsyncOperation)operation2.BundleRequest).progress));
							float? num2 = num;
							if (num2.HasValue)
							{
								text += $" {num2.Value:P0}";
							}
							Logger.LogDebug(text);
						}
					}
					<>2__current = null;
					<>1__state = 2;
					return true;
				}
				Logger.LogInfo("Finished loading bundles.");
				<disableLoadingUI>5__3();
				Utilities.SafeInvokeEvent(BundleLoader.OnAllBundlesLoaded);
				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();
			}
		}

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

			private object <>2__current;

			public LoadOperation operation;

			public AssetBundle bundle;

			private AssetBundleRequest <assetRequest>5__2;

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

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

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

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

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					operation.CurrentState = LoadOperation.State.LoadingContent;
					<assetRequest>5__2 = bundle.LoadAllAssetsAsync<ScriptableObject>();
					<>2__current = <assetRequest>5__2;
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					Object[] allAssets = <assetRequest>5__2.allAssets;
					Mod[] array = allAssets.OfType<Mod>().ToArray();
					int num = array.Length;
					if (num <= 1)
					{
						if (num == 0)
						{
							Logger.LogError("Bundle " + operation.FileName + " contains no mods!");
							return false;
						}
						Mod mod = array[0];
						foreach (Content item in allAssets.OfType<Content>())
						{
							try
							{
								item.Initialize(mod);
							}
							catch (Exception ex)
							{
								Logger.LogError($"Failed to load {item.Name} ({((object)item).GetType().Name}) from bundle {operation.FileName} ({mod.Identifier}): {ex}");
							}
						}
						return false;
					}
					Logger.LogError("Bundle " + operation.FileName + " contains more than one mod!");
					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();
			}
		}

		private static readonly List<LoadOperation> _operations = new List<LoadOperation>();

		public static event Action? OnAllBundlesLoaded;

		internal static void LoadAllBundles(string root, string withExtension)
		{
			Logger.LogInfo("Loading all bundles with extension " + withExtension + " from root " + root, extended: true);
			string[] files = Directory.GetFiles(root, "*" + withExtension, SearchOption.AllDirectories);
			string[] array = files;
			foreach (string path in array)
			{
				LoadBundleAndContent(path);
			}
		}

		public static void LoadBundleAndContent(string path)
		{
			LoadBundle(path, (Func<AssetBundle, IEnumerator>?)null, loadContents: true);
		}

		public static void LoadBundle(string path, Action<AssetBundle> onLoaded, bool loadContents = false)
		{
			<>c__DisplayClass6_0 CS$<>8__locals0 = new <>c__DisplayClass6_0();
			CS$<>8__locals0.onLoaded = onLoaded;
			LoadBundle(path, (Func<AssetBundle, IEnumerator>?)OnLoaded, loadContents);
			[IteratorStateMachine(typeof(<>c__DisplayClass6_0.<<LoadBundle>g__OnLoaded|0>d))]
			IEnumerator OnLoaded(AssetBundle bundle)
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <>c__DisplayClass6_0.<<LoadBundle>g__OnLoaded|0>d(0)
				{
					<>4__this = CS$<>8__locals0,
					bundle = bundle
				};
			}
		}

		public static void LoadBundle(string path, Func<AssetBundle, IEnumerator>? onLoaded = null, bool loadContents = false)
		{
			Logger.LogInfo("Loading bundle at " + path + "...");
			_operations.Add(new LoadOperation(path, onLoaded, loadContents));
		}

		internal static void FinishLoadOperations(MonoBehaviour behaviour)
		{
			behaviour.StartCoroutine(FinishLoadOperationsRoutine(behaviour));
		}

		[IteratorStateMachine(typeof(<FinishLoadOperationsRoutine>d__9))]
		private static IEnumerator FinishLoadOperationsRoutine(MonoBehaviour behaviour)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FinishLoadOperationsRoutine>d__9(0)
			{
				behaviour = behaviour
			};
		}

		private static (TMP_Text, Action) SetupLoadingUI()
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.Find("HUD Canvas");
			Transform hud = val.transform.Find("HUD");
			((Component)hud).gameObject.SetActive(false);
			TMP_Text val2 = Object.FindObjectOfType<TMP_Text>();
			TMP_Text text = Object.Instantiate<TMP_Text>(val2, val.transform);
			((Object)((Component)text).gameObject).name = "REPOLibText";
			((Component)text).gameObject.SetActive(true);
			text.text = "REPOLib is loading bundles... Hang tight!";
			((Graphic)text).color = Color.white;
			text.alignment = (TextAlignmentOptions)514;
			RectTransform component = ((Component)text).GetComponent<RectTransform>();
			component.anchoredPosition = Vector2.zero;
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.sizeDelta = Vector2.zero;
			return (text, delegate
			{
				((Component)text).gameObject.SetActive(false);
				((Component)hud).gameObject.SetActive(true);
			});
		}

		[IteratorStateMachine(typeof(<FinishLoadOperation>d__11))]
		private static IEnumerator FinishLoadOperation(LoadOperation operation)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FinishLoadOperation>d__11(0)
			{
				operation = operation
			};
		}

		[IteratorStateMachine(typeof(<LoadBundleContent>d__12))]
		private static IEnumerator LoadBundleContent(LoadOperation operation, AssetBundle bundle)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadBundleContent>d__12(0)
			{
				operation = operation,
				bundle = bundle
			};
		}

		[Obsolete("Use LoadBundleAndContent instead")]
		public static void LoadBundle(string path, string relativePath)
		{
			LoadBundleAndContent(path);
		}

		[CompilerGenerated]
		internal static void <FinishLoadOperation>g__Finish|11_0(ref <>c__DisplayClass11_0 P_0)
		{
			_operations.Remove(P_0.operation);
		}
	}
	internal static class ConfigManager
	{
		public static ConfigFile ConfigFile { get; private set; }

		public static ConfigEntry<bool> ExtendedLogging { get; private set; }

		public static ConfigEntry<bool> DeveloperMode { get; private set; }

		public static ConfigEntry<bool> VanillaDeveloperMode { get; private set; }

		public static void Initialize(ConfigFile configFile)
		{
			ConfigFile = configFile;
			BindConfigs();
		}

		private static void BindConfigs()
		{
			ExtendedLogging = ConfigFile.Bind<bool>("General", "ExtendedLogging", false, "Enable extended logging.");
			DeveloperMode = ConfigFile.Bind<bool>("General", "DeveloperMode", false, "Enable developer mode cheats for testing.");
			VanillaDeveloperMode = ConfigFile.Bind<bool>("General", "VanillaDeveloperMode", false, "Enable vanilla developer mode cheats for testing.");
			VanillaDeveloperMode.SettingChanged += delegate
			{
				SteamManagerPatch.UpdateDeveloperMode();
			};
		}
	}
	internal static class Logger
	{
		public static ManualLogSource ManualLogSource { get; private set; }

		public static void Initialize(ManualLogSource manualLogSource)
		{
			ManualLogSource = manualLogSource;
		}

		public static void LogDebug(object data, bool extended = true)
		{
			Log((LogLevel)32, data, extended);
		}

		public static void LogInfo(object data, bool extended = false)
		{
			Log((LogLevel)16, data, extended);
		}

		public static void LogWarning(object data, bool extended = false)
		{
			Log((LogLevel)4, data, extended);
		}

		public static void LogError(object data, bool extended = false)
		{
			Log((LogLevel)2, data, extended);
		}

		public static void LogFatal(object data, bool extended = false)
		{
			Log((LogLevel)1, data, extended);
		}

		public static void Log(LogLevel logLevel, object data, bool extended = false)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!extended || IsExtendedLoggingEnabled())
			{
				ManualLogSource manualLogSource = ManualLogSource;
				if (manualLogSource != null)
				{
					manualLogSource.Log(logLevel, data);
				}
			}
		}

		public static bool IsExtendedLoggingEnabled()
		{
			if (ConfigManager.ExtendedLogging == null)
			{
				return false;
			}
			return ConfigManager.ExtendedLogging.Value;
		}
	}
	[BepInPlugin("REPOLib", "REPOLib", "2.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		private readonly Harmony _harmony = new Harmony("REPOLib");

		public static Plugin Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			Logger.Initialize(Logger.CreateLogSource("REPOLib"));
			Logger.LogInfo("REPOLib has awoken!");
			_harmony.PatchAll(typeof(RunManagerPatch));
			_harmony.PatchAll(typeof(EnemyDirectorPatch));
			_harmony.PatchAll(typeof(StatsManagerPatch));
			_harmony.PatchAll(typeof(SemiFuncPatch));
			_harmony.PatchAll(typeof(AudioManagerPatch));
			_harmony.PatchAll(typeof(SteamManagerPatch));
			_harmony.PatchAll(typeof(EnemyGnomeDirectorPatch));
			_harmony.PatchAll(typeof(EnemyBangDirectorPatch));
			ConfigManager.Initialize(((BaseUnityPlugin)this).Config);
			BundleLoader.LoadAllBundles(Paths.PluginPath, ".repobundle");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "REPOLib";

		public const string PLUGIN_NAME = "REPOLib";

		public const string PLUGIN_VERSION = "2.0.1";
	}
}
namespace REPOLib.Patches
{
	[HarmonyPatch(typeof(AudioManager))]
	internal static class AudioManagerPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPatch()
		{
			Utilities.FixAudioMixerGroupsOnPrefabs();
		}
	}
	[HarmonyPatch(typeof(EnemyBangDirector))]
	internal static class EnemyBangDirectorPatch
	{
		[CompilerGenerated]
		private sealed class <PreSetup>d__1 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public EnemyBangDirector instance;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (LevelGenerator.Instance.Generated)
					{
						<>2__current = (object)new WaitForSeconds(0.1f);
						<>1__state = 1;
						return true;
					}
					goto IL_004e;
				case 1:
					<>1__state = -1;
					goto IL_004e;
				case 2:
					{
						<>1__state = -1;
						return false;
					}
					IL_004e:
					<>2__current = instance.Setup();
					<>1__state = 2;
					return true;
				}
			}

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

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

		[HarmonyPatch("Awake")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> AwakeTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(EnemyBangDirector), "Setup", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(EnemyBangDirectorPatch), "PreSetup", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				Logger.LogError("EnemyBangDirectorPatch: failed to find required methods for AwakeTranspiler.");
				return instructions;
			}
			List<CodeInstruction> list = new List<CodeInstruction>();
			foreach (CodeInstruction instruction in instructions)
			{
				if ((instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt) && instruction.operand is MethodInfo methodInfo3 && methodInfo3 == methodInfo)
				{
					list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo2));
					Logger.LogDebug("EnemyBangDirectorPatch: AwakeTranspiler replaced " + methodInfo.Name + " call with " + methodInfo2.Name + ".");
				}
				else
				{
					list.Add(instruction);
				}
			}
			return list.AsEnumerable();
		}

		[IteratorStateMachine(typeof(<PreSetup>d__1))]
		private static IEnumerator PreSetup(EnemyBangDirector instance)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PreSetup>d__1(0)
			{
				instance = instance
			};
		}
	}
	[HarmonyPatch(typeof(EnemyDirector))]
	internal static class EnemyDirectorPatch
	{
		private static bool _alreadyRegistered;

		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void AwakePatch()
		{
			if (_alreadyRegistered)
			{
				foreach (EnemySetup registeredEnemy in Enemies.RegisteredEnemies)
				{
					EnemyDirector.instance.AddEnemy(registeredEnemy);
				}
				return;
			}
			Enemies.RegisterInitialEnemies();
			_alreadyRegistered = true;
		}
	}
	[HarmonyPatch(typeof(EnemyGnomeDirector))]
	internal static class EnemyGnomeDirectorPatch
	{
		[CompilerGenerated]
		private sealed class <PreSetup>d__1 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public EnemyGnomeDirector instance;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (LevelGenerator.Instance.Generated)
					{
						<>2__current = (object)new WaitForSeconds(0.1f);
						<>1__state = 1;
						return true;
					}
					goto IL_004e;
				case 1:
					<>1__state = -1;
					goto IL_004e;
				case 2:
					{
						<>1__state = -1;
						return false;
					}
					IL_004e:
					<>2__current = instance.Setup();
					<>1__state = 2;
					return true;
				}
			}

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

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

		[HarmonyPatch("Awake")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> AwakeTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(EnemyGnomeDirector), "Setup", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(EnemyGnomeDirectorPatch), "PreSetup", (Type[])null, (Type[])null);
			if (methodInfo == null || methodInfo2 == null)
			{
				Logger.LogError("EnemyGnomeDirectorPatch: failed to find required methods for AwakeTranspiler.");
				return instructions;
			}
			List<CodeInstruction> list = new List<CodeInstruction>();
			foreach (CodeInstruction instruction in instructions)
			{
				if ((instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt) && instruction.operand is MethodInfo methodInfo3 && methodInfo3 == methodInfo)
				{
					list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo2));
					Logger.LogDebug("EnemyGnomeDirectorPatch: AwakeTranspiler replaced " + methodInfo.Name + " call with " + methodInfo2.Name + ".");
				}
				else
				{
					list.Add(instruction);
				}
			}
			return list.AsEnumerable();
		}

		[IteratorStateMachine(typeof(<PreSetup>d__1))]
		private static IEnumerator PreSetup(EnemyGnomeDirector instance)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <PreSetup>d__1(0)
			{
				instance = instance
			};
		}
	}
	[HarmonyPatch(typeof(RunManager))]
	internal static class RunManagerPatch
	{
		private static bool _patchedAwake;

		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void AwakePatch(RunManager __instance)
		{
			if (!_patchedAwake)
			{
				_patchedAwake = true;
				NetworkPrefabs.Initialize();
				NetworkingEvents.Initialize();
				Levels.RegisterInitialLevels();
				Valuables.RegisterInitialValuables();
				BundleLoader.OnAllBundlesLoaded += CommandManager.Initialize;
				BundleLoader.FinishLoadOperations((MonoBehaviour)(object)__instance);
			}
		}
	}
	[HarmonyPatch(typeof(SemiFunc))]
	internal static class SemiFuncPatch
	{
		[HarmonyPatch("Command")]
		[HarmonyPrefix]
		private static bool CommandPatch(string _command)
		{
			if (_command.StartsWith("/"))
			{
				return Command(_command);
			}
			return true;
		}

		private static bool Command(string message)
		{
			string text = message.ToLower();
			string text2 = text.Split(' ')[0].Substring(1);
			string text3 = "";
			if (text.Length > text2.Length)
			{
				text3 = text.Substring(text2.Length + 1).Trim();
			}
			CommandManager.CommandExecutionMethods.TryGetValue(text2, out MethodInfo value);
			if (value != null)
			{
				CommandExecutionAttribute customAttribute = value.GetCustomAttribute<CommandExecutionAttribute>();
				if (CommandManager.CommandsEnabled.TryGetValue(customAttribute.Name, out var value2) && !value2)
				{
					return false;
				}
				if (customAttribute != null && customAttribute.RequiresDeveloperMode && !ConfigManager.DeveloperMode.Value)
				{
					Logger.LogWarning("Command " + text2 + " requires developer mode to be enabled. Enable it in REPOLib.cfg");
					return false;
				}
				try
				{
					ParameterInfo[] parameters = value.GetParameters();
					if (parameters.Length == 0)
					{
						value.Invoke(null, null);
					}
					else
					{
						value.Invoke(null, new object[1] { text3 });
					}
				}
				catch (Exception arg)
				{
					Logger.LogError($"Error executing command: {arg}");
				}
				return false;
			}
			return true;
		}

		[HarmonyPatch("EnemySpawn")]
		[HarmonyPrefix]
		private static bool EnemySpawnPatch(ref bool __result)
		{
			if (Enemies.SpawnNextEnemiesNotDespawned > 0)
			{
				Enemies.SpawnNextEnemiesNotDespawned--;
				__result = true;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(StatsManager))]
	internal static class StatsManagerPatch
	{
		[HarmonyPatch("RunStartStats")]
		[HarmonyPostfix]
		private static void RunStartStatsPatch()
		{
			Items.RegisterItems();
		}
	}
	[HarmonyPatch(typeof(SteamManager))]
	internal static class SteamManagerPatch
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		public static void AwakePatch(SteamManager __instance)
		{
			UpdateDeveloperMode();
		}

		public static void UpdateDeveloperMode()
		{
			if (ConfigManager.VanillaDeveloperMode == null || (Object)(object)SteamManager.instance == (Object)null)
			{
				return;
			}
			bool value = ConfigManager.VanillaDeveloperMode.Value;
			if (SteamManager.instance.developerMode != value)
			{
				if (value)
				{
					Logger.LogInfo("Enabling vanilla developer mode.");
				}
				else
				{
					Logger.LogInfo("Disabling vanilla developer mode.");
				}
			}
			SteamManager.instance.developerMode = value;
		}
	}
}
namespace REPOLib.Objects
{
	public class CustomPrefabPool : IPunPrefabPool
	{
		public readonly Dictionary<string, GameObject> Prefabs = new Dictionary<string, GameObject>();

		private DefaultPool? _defaultPool;

		public DefaultPool DefaultPool
		{
			get
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Expected O, but got Unknown
				if (_defaultPool == null)
				{
					_defaultPool = new DefaultPool();
				}
				return _defaultPool;
			}
			set
			{
				if (value != null)
				{
					_defaultPool = value;
				}
			}
		}

		public bool RegisterPrefab(string prefabId, GameObject prefab)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)prefab == (Object)null)
			{
				throw new ArgumentException("CustomPrefabPool: failed to register network prefab. Prefab is null.");
			}
			if (string.IsNullOrWhiteSpace(prefabId))
			{
				throw new ArgumentException("CustomPrefabPool: failed to register network prefab. PrefabId is invalid.");
			}
			if (ResourcesHelper.HasPrefab(prefabId))
			{
				Logger.LogError("CustomPrefabPool: failed to register network prefab \"" + prefabId + "\". Prefab already exists in Resources with the same prefab id.");
				return false;
			}
			if (Prefabs.TryGetValue(prefabId, out GameObject value, ignoreKeyCase: true))
			{
				LogLevel logLevel = (LogLevel)(((Object)(object)value == (Object)(object)prefab) ? 4 : 2);
				Logger.Log(logLevel, "CustomPrefabPool: failed to register network prefab \"" + prefabId + "\". There is already a prefab registered with the same prefab id.");
				return false;
			}
			Prefabs[prefabId] = prefab;
			Logger.LogDebug("CustomPrefabPool: registered network prefab \"" + prefabId + "\"");
			return true;
		}

		public bool HasPrefab(GameObject prefab)
		{
			if (Prefabs.ContainsValue(prefab))
			{
				return true;
			}
			if (ResourcesHelper.HasPrefab(prefab))
			{
				return true;
			}
			return false;
		}

		public bool HasPrefab(string prefabId)
		{
			if (Prefabs.ContainsKey(prefabId, ignoreKeyCase: true))
			{
				return true;
			}
			if (ResourcesHelper.HasPrefab(prefabId))
			{
				return true;
			}
			return false;
		}

		public string? GetPrefabId(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				Logger.LogError("Failed to get prefab id. GameObject is null.");
				return string.Empty;
			}
			return Prefabs.GetKeyOrDefault(prefab);
		}

		public GameObject? GetPrefab(string prefabId)
		{
			return Prefabs.GetValueOrDefault(prefabId, ignoreKeyCase: true);
		}

		public GameObject? Instantiate(string prefabId, Vector3 position, Quaternion rotation)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(prefabId))
			{
				throw new ArgumentException("CustomPrefabPool: failed to spawn network prefab. PrefabId is null.");
			}
			GameObject val;
			if (!Prefabs.TryGetValue(prefabId, out GameObject value, ignoreKeyCase: true))
			{
				val = DefaultPool.Instantiate(prefabId, position, rotation);
				if ((Object)(object)val == (Object)null)
				{
					Logger.LogError("CustomPrefabPool: failed to spawn network prefab \"" + prefabId + "\". GameObject is null.");
				}
				return val;
			}
			bool activeSelf = value.activeSelf;
			if (activeSelf)
			{
				value.SetActive(false);
			}
			val = Object.Instantiate<GameObject>(value, position, rotation);
			if (activeSelf)
			{
				value.SetActive(true);
			}
			Logger.LogInfo($"CustomPrefabPool: spawned network prefab \"{prefabId}\" at position {position}, rotation {((Quaternion)(ref rotation)).eulerAngles}", extended: true);
			return val;
		}

		public void Destroy(GameObject gameObject)
		{
			Object.Destroy((Object)(object)gameObject);
		}
	}
	public class UnityObjectNameComparer<T> : IEqualityComparer<T> where T : Object
	{
		public StringComparison ComparisonType { get; private set; }

		public UnityObjectNameComparer(StringComparison comparisonType = StringComparison.OrdinalIgnoreCase)
		{
			ComparisonType = comparisonType;
		}

		public bool Equals(T x, T y)
		{
			if ((Object)(object)x == (Object)(object)y)
			{
				return true;
			}
			if ((Object)(object)x == (Object)null || (Object)(object)y == (Object)null)
			{
				return false;
			}
			return ((Object)x).name.Equals(((Object)y).name, ComparisonType);
		}

		public int GetHashCode(T obj)
		{
			if (!((Object)(object)obj != (Object)null))
			{
				return 0;
			}
			return ((Object)obj).name.GetHashCode();
		}
	}
}
namespace REPOLib.Objects.Sdk
{
	public abstract class Content : ScriptableObject
	{
		public abstract string Name { get; }

		public abstract void Initialize(Mod mod);
	}
	[CreateAssetMenu(menuName = "REPOLib/Enemy", order = 3, fileName = "New Enemy")]
	public class EnemyContent : Content
	{
		[SerializeField]
		private EnemySetup _setup;

		public EnemySetup Setup => _setup;

		public override string Name
		{
			get
			{
				EnemySetup setup = Setup;
				return ((setup != null) ? ((Object)setup).name : null) ?? string.Empty;
			}
		}

		public override void Initialize(Mod mod)
		{
			Enemies.RegisterEnemy(Setup);
		}
	}
	[CreateAssetMenu(menuName = "REPOLib/Item", order = 2, fileName = "New Item")]
	public class ItemContent : Content
	{
		[SerializeField]
		private ItemAttributes _prefab;

		public ItemAttributes Prefab => _prefab;

		public override string Name
		{
			get
			{
				ItemAttributes prefab = Prefab;
				return ((prefab != null) ? ((Object)prefab).name : null) ?? string.Empty;
			}
		}

		public override void Initialize(Mod mod)
		{
			_prefab.item.prefab = ((Component)_prefab).gameObject;
			Items.RegisterItem(Prefab.item);
		}
	}
	[CreateAssetMenu(menuName = "REPOLib/Level", order = 4, fileName = "New Level")]
	public class LevelContent : Content
	{
		[SerializeField]
		private Level _level;

		public Level Level => _level;

		public override string Name
		{
			get
			{
				Level level = Level;
				return ((level != null) ? ((Object)level).name : null) ?? string.Empty;
			}
		}

		public override void Initialize(Mod mod)
		{
			Levels.RegisterLevel(Level);
		}
	}
	[CreateAssetMenu(menuName = "REPOLib/Mod", order = 0, fileName = "New Mod")]
	public class Mod : ScriptableObject
	{
		[SerializeField]
		private string _name;

		[SerializeField]
		private string _author;

		[SerializeField]
		private string _version = "1.0.0";

		[SerializeField]
		private string _description;

		[SerializeField]
		private string _websiteUrl;

		[SerializeField]
		private string[] _dependencies = new string[1] { "Zehs-REPOLib-2.0.1" };

		[SerializeField]
		private Sprite _icon;

		[SerializeField]
		private TextAsset _readme;

		public string Name => _name;

		public string Author => _author;

		public string Version => _version;

		public string Description => _description;

		public string WebsiteUrl => _websiteUrl;

		public IReadOnlyList<string> Dependencies => _dependencies;

		public Sprite Icon => _icon;

		public TextAsset Readme => _readme;

		public string FullName => Author + "-" + Name;

		public string Identifier => Author + "-" + Name + "-" + Version;
	}
	[CreateAssetMenu(menuName = "REPOLib/Valuable", order = 1, fileName = "New Valuable")]
	public class ValuableContent : Content
	{
		[SerializeField]
		private ValuableObject _prefab;

		[SerializeField]
		private string[] _valuablePresets = new string[1] { "Valuables - Generic" };

		public ValuableObject Prefab => _prefab;

		public IReadOnlyList<string> ValuablePresets => _valuablePresets;

		public override string Name
		{
			get
			{
				ValuableObject prefab = Prefab;
				return ((prefab != null) ? ((Object)prefab).name : null) ?? string.Empty;
			}
		}

		public override void Initialize(Mod mod)
		{
			Valuables.RegisterValuable(((Component)Prefab).gameObject, ValuablePresets.ToList());
		}
	}
}
namespace REPOLib.Modules
{
	public static class Enemies
	{
		internal static int SpawnNextEnemiesNotDespawned = 0;

		private static readonly List<EnemySetup> _enemiesToRegister = new List<EnemySetup>();

		private static readonly List<EnemySetup> _enemiesRegistered = new List<EnemySetup>();

		private static bool _initialEnemiesRegistered;

		public static IReadOnlyList<EnemySetup> AllEnemies => GetEnemies();

		public static IReadOnlyList<EnemySetup> RegisteredEnemies => _enemiesRegistered;

		internal static void RegisterInitialEnemies()
		{
			if (_initialEnemiesRegistered)
			{
				return;
			}
			foreach (EnemySetup item in _enemiesToRegister)
			{
				RegisterEnemyWithGame(item);
			}
			_enemiesToRegister.Clear();
			_initialEnemiesRegistered = true;
		}

		private static void RegisterEnemyWithGame(EnemySetup enemy)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (!_enemiesRegistered.Contains(enemy) && enemy.TryGetEnemyParent(out EnemyParent enemyParent))
			{
				if (EnemyDirector.instance.AddEnemy(enemy))
				{
					_enemiesRegistered.Add(enemy);
					Logger.LogInfo($"Added enemy \"{enemyParent.enemyName}\" to difficulty {enemyParent.difficulty}", extended: true);
				}
				else
				{
					Logger.LogWarning($"Failed to add enemy \"{enemyParent.enemyName}\" to difficulty {enemyParent.difficulty}", extended: true);
				}
			}
		}

		public static void RegisterEnemy(EnemySetup enemySetup)
		{
			if ((Object)(object)enemySetup == (Object)null || enemySetup.spawnObjects == null || enemySetup.spawnObjects.Count == 0)
			{
				throw new ArgumentException("Failed to register enemy. EnemySetup or spawnObjects list is empty.");
			}
			EnemyParent enemyParent = enemySetup.GetEnemyParent();
			if ((Object)(object)enemyParent == (Object)null)
			{
				Logger.LogError("Failed to register enemy \"" + ((Object)enemySetup).name + "\". No enemy prefab found in spawnObjects list.");
				return;
			}
			if (ResourcesHelper.HasEnemyPrefab(enemySetup))
			{
				Logger.LogError("Failed to register enemy \"" + enemyParent.enemyName + "\". Enemy prefab already exists in Resources with the same name.");
				return;
			}
			if (_enemiesToRegister.Contains(enemySetup))
			{
				Logger.LogError("Failed to register enemy \"" + enemyParent.enemyName + "\". Enemy is already registered!");
				return;
			}
			foreach (GameObject distinctSpawnObject in enemySetup.GetDistinctSpawnObjects())
			{
				foreach (EnemySetup item in _enemiesToRegister)
				{
					if (item.AnySpawnObjectsNameEqualsThatIsNotTheSameObject(distinctSpawnObject))
					{
						Logger.LogError("Failed to register enemy \"" + enemyParent.enemyName + "\". Enemy \"" + ((Object)item).name + "\" already has a spawn object called \"" + ((Object)distinctSpawnObject).name + "\"");
						return;
					}
				}
			}
			foreach (GameObject distinctSpawnObject2 in enemySetup.GetDistinctSpawnObjects())
			{
				string enemyPrefabPath = ResourcesHelper.GetEnemyPrefabPath(distinctSpawnObject2);
				if (!NetworkPrefabs.HasNetworkPrefab(enemyPrefabPath))
				{
					NetworkPrefabs.RegisterNetworkPrefab(enemyPrefabPath, distinctSpawnObject2);
				}
				Utilities.FixAudioMixerGroups(distinctSpawnObject2);
			}
			if (_initialEnemiesRegistered)
			{
				RegisterEnemyWithGame(enemySetup);
			}
			else
			{
				_enemiesToRegister.Add(enemySetup);
			}
		}

		public static List<EnemyParent>? SpawnEnemy(EnemySetup enemySetup, Vector3 position, Quaternion rotation, bool spawnDespawned = true)
		{
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)enemySetup == (Object)null)
			{
				Logger.LogError("Failed to spawn enemy. EnemySetup is null.");
				return null;
			}
			if (!enemySetup.TryGetEnemyParent(out EnemyParent enemyParent))
			{
				Logger.LogError("Failed to spawn enemy. EnemyParent is null.");
				return null;
			}
			if ((Object)(object)LevelGenerator.Instance == (Object)null)
			{
				Logger.LogError("Failed to spawn enemy \"" + enemyParent.enemyName + "\". EnemySetup instance is null.");
				return null;
			}
			if ((Object)(object)RunManager.instance == (Object)null)
			{
				Logger.LogError("Failed to spawn enemy \"" + enemyParent.enemyName + "\". RunManager instance is null.");
				return null;
			}
			if ((Object)(object)EnemyDirector.instance == (Object)null)
			{
				Logger.LogError("Failed to spawn enemy \"" + enemyParent.enemyName + "\". EnemyDirector instance is null.");
				return null;
			}
			List<EnemyParent> list = new List<EnemyParent>();
			EnemyParent val2 = default(EnemyParent);
			foreach (GameObject sortedSpawnObject in enemySetup.GetSortedSpawnObjects())
			{
				if ((Object)(object)sortedSpawnObject == (Object)null)
				{
					Logger.LogError("Failed to spawn enemy \"" + enemyParent.enemyName + "\" spawn object. GameObject is null.");
					continue;
				}
				string enemyPrefabPath = ResourcesHelper.GetEnemyPrefabPath(sortedSpawnObject);
				GameObject val = NetworkPrefabs.SpawnNetworkPrefab(enemyPrefabPath, position, rotation, 0);
				if ((Object)(object)val == (Object)null)
				{
					Logger.LogError("Failed to spawn enemy \"" + enemyParent.enemyName + "\" spawn object \"" + ((Object)sortedSpawnObject).name + "\"");
				}
				else if (val.TryGetComponent<EnemyParent>(ref val2))
				{
					list.Add(val2);
					if (!spawnDespawned)
					{
						SpawnNextEnemiesNotDespawned++;
					}
					val2.SetupDone = true;
					Enemy componentInChildren = val.GetComponentInChildren<Enemy>();
					if ((Object)(object)componentInChildren != (Object)null)
					{
						componentInChildren.EnemyTeleported(position);
					}
					else
					{
						Logger.LogError("Enemy \"" + enemyParent.enemyName + "\" spawn object \"" + ((Object)sortedSpawnObject).name + "\" does not have an enemy component.");
					}
					LevelGenerator instance = LevelGenerator.Instance;
					instance.EnemiesSpawnTarget++;
					EnemyDirector.instance.FirstSpawnPointAdd(val2);
				}
			}
			if (list.Count == 0)
			{
				Logger.LogInfo("Failed to spawn enemy \"" + enemyParent.enemyName + "\". No spawn objects where spawned.", extended: true);
				return list;
			}
			Logger.LogInfo($"Spawned enemy \"{enemyParent.enemyName}\" at position {position}", extended: true);
			RunManager.instance.EnemiesSpawnedRemoveEnd();
			return list;
		}

		public static IReadOnlyList<EnemySetup> GetEnemies()
		{
			if ((Object)(object)EnemyDirector.instance == (Object)null)
			{
				return Array.Empty<EnemySetup>();
			}
			return EnemyDirector.instance.GetEnemies();
		}

		public static bool TryGetEnemyByName(string name, [NotNullWhen(true)] out EnemySetup? enemySetup)
		{
			enemySetup = GetEnemyByName(name);
			return (Object)(object)enemySetup != (Object)null;
		}

		public static EnemySetup? GetEnemyByName(string name)
		{
			return EnemyDirector.instance?.GetEnemyByName(name);
		}

		public static bool TryGetEnemyThatContainsName(string name, [NotNullWhen(true)] out EnemySetup? enemySetup)
		{
			enemySetup = GetEnemyThatContainsName(name);
			return (Object)(object)enemySetup != (Object)null;
		}

		public static EnemySetup? GetEnemyThatContainsName(string name)
		{
			return EnemyDirector.instance?.GetEnemyThatContainsName(name);
		}
	}
	public static class Items
	{
		private static readonly List<Item> _itemsToRegister = new List<Item>();

		private static readonly List<Item> _itemsRegistered = new List<Item>();

		private static bool _initialItemsRegistered;

		public static IReadOnlyList<Item> AllItems => GetItems();

		public static IReadOnlyList<Item> RegisteredItems => _itemsRegistered;

		internal static void RegisterItems()
		{
			if ((Object)(object)StatsManager.instance == (Object)null)
			{
				Logger.LogError("Failed to register items. StatsManager instance is null.");
				return;
			}
			Logger.LogInfo("Adding items.");
			foreach (Item item in _itemsToRegister)
			{
				RegisterItemWithGame(item);
			}
			_initialItemsRegistered = true;
		}

		private static void RegisterItemWithGame(Item item)
		{
			Utilities.FixAudioMixerGroups(item.prefab);
			if (StatsManager.instance.AddItem(item))
			{
				if (!_itemsRegistered.Contains(item))
				{
					_itemsRegistered.Add(item);
				}
				Logger.LogInfo("Added item \"" + item.itemName + "\"", extended: true);
			}
			else
			{
				Logger.LogWarning("Failed to add item \"" + item.itemName + "\"", extended: true);
			}
		}

		public static void RegisterItem(Item item)
		{
			Item item2 = item;
			if ((Object)(object)item2 == (Object)null)
			{
				throw new ArgumentException("Failed to register item. Item is null.");
			}
			if ((Object)(object)item2.prefab == (Object)null)
			{
				Logger.LogError("Failed to register item \"" + item2.itemName + "\". Item prefab is null.");
				return;
			}
			if (item2.itemAssetName != ((Object)item2.prefab).name)
			{
				Logger.LogError("Failed to register item \"" + item2.itemName + "\". Item itemAssetName does not match the prefab name.");
				return;
			}
			if (ResourcesHelper.HasItemPrefab(item2))
			{
				Logger.LogError("Failed to register item \"" + item2.itemName + "\". Item prefab already exists in Resources with the same name.");
				return;
			}
			if (_itemsToRegister.Any((Item x) => x.itemAssetName == item2.itemAssetName))
			{
				Logger.LogError("Failed to register item \"" + item2.itemName + "\". Item prefab already exists with the same name.");
				return;
			}
			if (_itemsToRegister.Contains(item2))
			{
				Logger.LogError("Failed to register item \"" + item2.itemName + "\". Item is already registered!");
				return;
			}
			string itemPrefabPath = ResourcesHelper.GetItemPrefabPath(item2);
			NetworkPrefabs.RegisterNetworkPrefab(itemPrefabPath, item2.prefab);
			_itemsToRegister.Add(item2);
			if (_initialItemsRegistered)
			{
				RegisterItemWithGame(item2);
			}
		}

		public static GameObject? SpawnItem(Item item, Vector3 position, Quaternion rotation)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null)
			{
				Logger.LogError("Failed to spawn item. Item is null.");
				return null;
			}
			if ((Object)(object)item.prefab == (Object)null)
			{
				Logger.LogError("Failed to spawn item. Prefab is null.");
				return null;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				Logger.LogError("Failed to spawn item \"" + item.itemName + "\". You are not the host.");
				return null;
			}
			string itemPrefabPath = ResourcesHelper.GetItemPrefabPath(item);
			GameObject val = NetworkPrefabs.SpawnNetworkPrefab(itemPrefabPath, position, rotation, 0);
			if ((Object)(object)val == (Object)null)
			{
				Logger.LogError("Failed to spawn item \"" + item.itemName + "\"");
				return null;
			}
			Logger.LogInfo($"Spawned item \"{item.itemName}\" at position {position}, rotation: {((Quaternion)(ref rotation)).eulerAngles}", extended: true);
			return val;
		}

		public static IReadOnlyList<Item> GetItems()
		{
			if ((Object)(object)StatsManager.instance == (Object)null)
			{
				return Array.Empty<Item>();
			}
			return StatsManager.instance.GetItems();
		}

		public static bool TryGetItemByName(string name, [NotNullWhen(true)] out Item? item)
		{
			item = GetItemByName(name);
			return (Object)(object)item != (Object)null;
		}

		public static Item? GetItemByName(string name)
		{
			return StatsManager.instance?.GetItemByName(name);
		}

		public static bool TryGetItemThatContainsName(string name, [NotNullWhen(true)] out Item? item)
		{
			item = GetItemThatContainsName(name);
			return (Object)(object)item != (Object)null;
		}

		public static Item? GetItemThatContainsName(string name)
		{
			return StatsManager.instance?.GetItemThatContainsName(name);
		}
	}
	public static class Levels
	{
		private static readonly List<Level> _levelsToRegister = new List<Level>();

		private static readonly List<Level> _levelsRegistered = new List<Level>();

		private static bool _initialLevelsRegistered;

		public static IReadOnlyList<Level> AllLevels => GetLevels();

		public static IReadOnlyList<Level> RegisteredLevels => _levelsRegistered;

		internal static void RegisterInitialLevels()
		{
			if (_initialLevelsRegistered)
			{
				return;
			}
			ValuablePresets.CacheValuablePresets();
			Logger.LogInfo("Adding levels.");
			foreach (Level item in _levelsToRegister)
			{
				RegisterLevelWithGame(item);
			}
			_levelsToRegister.Clear();
			_initialLevelsRegistered = true;
		}

		private static void RegisterLevelWithGame(Level level)
		{
			if (_levelsRegistered.Contains(level))
			{
				return;
			}
			if (level.ValuablePresets.Count == 0)
			{
				Logger.LogWarning("Level \"" + ((Object)level).name + "\" does not have any valuable presets! Adding generic preset.");
				level.ValuablePresets.Add(ValuablePresets.GenericPreset);
			}
			for (int i = 0; i < level.ValuablePresets.Count; i++)
			{
				LevelValuables val = level.ValuablePresets[i];
				if (ValuablePresets.AllValuablePresets.Values.Contains(val))
				{
					continue;
				}
				if (ValuablePresets.AllValuablePresets.TryGetValue(((Object)val).name, out LevelValuables value))
				{
					if (val.GetCombinedList().Count > 0)
					{
						Logger.LogWarning("Proxy preset \"" + ((Object)val).name + "\" in level \"" + ((Object)level).name + "\" contains valuables! This likely caused duplicate valuables to load!");
					}
					level.ValuablePresets[i] = value;
					Logger.LogInfo("Replaced proxy preset \"" + ((Object)val).name + "\" in level \"" + ((Object)level).name + "\".", extended: true);
				}
				else
				{
					ValuablePresets.RegisterValuablePreset(val);
					Logger.LogInfo("Registered valuable preset \"" + ((Object)val).name + "\" from \"" + ((Object)level).name + "\".", extended: true);
				}
			}
			RunManager.instance.levels.Add(level);
			Logger.LogInfo("Added level \"" + ((Object)level).name + "\"", extended: true);
			_levelsRegistered.Add(level);
		}

		public static void RegisterLevel(Level level)
		{
			Level level2 = level;
			if ((Object)(object)level2 == (Object)null)
			{
				Logger.LogError("Failed to register level. Level is null.");
				return;
			}
			if (_levelsToRegister.Any((Level x) => ((Object)x).name.Equals(((Object)level2).name, StringComparison.OrdinalIgnoreCase)))
			{
				Logger.LogError("Failed to register level \"" + ((Object)level2).name + "\". Level already exists with the same name.");
				return;
			}
			if (_levelsToRegister.Contains(level2))
			{
				Logger.LogWarning("Failed to register level \"" + ((Object)level2).name + "\". Level is already registered!");
				return;
			}
			List<(GameObject, ResourcesHelper.LevelPrefabType)> list2 = (from prefab in new List<GameObject>[12]
				{
					level2.ModulesExtraction1, level2.ModulesExtraction2, level2.ModulesExtraction3, level2.ModulesNormal1, level2.ModulesNormal2, level2.ModulesNormal3, level2.ModulesPassage1, level2.ModulesPassage2, level2.ModulesPassage3, level2.ModulesDeadEnd1,
					level2.ModulesDeadEnd2, level2.ModulesDeadEnd3
				}.SelectMany((List<GameObject> list) => list)
				select (prefab, ResourcesHelper.LevelPrefabType.Module)).ToList();
			foreach (GameObject startRoom in level2.StartRooms)
			{
				list2.Add((startRoom, ResourcesHelper.LevelPrefabType.StartRoom));
			}
			if ((Object)(object)level2.ConnectObject != (Object)null)
			{
				list2.Add((level2.ConnectObject, ResourcesHelper.LevelPrefabType.Other));
			}
			if ((Object)(object)level2.BlockObject != (Object)null)
			{
				list2.Add((level2.BlockObject, ResourcesHelper.LevelPrefabType.Other));
			}
			foreach (var item3 in list2)
			{
				GameObject item = item3.Item1;
				ResourcesHelper.LevelPrefabType item2 = item3.Item2;
				string levelPrefabPath = ResourcesHelper.GetLevelPrefabPath(level2, item, item2);
				if (!ResourcesHelper.HasPrefab(levelPrefabPath))
				{
					NetworkPrefabs.RegisterNetworkPrefab(levelPrefabPath, item);
					Utilities.FixAudioMixerGroups(item);
				}
			}
			if (_initialLevelsRegistered)
			{
				RegisterLevelWithGame(level2);
			}
			else
			{
				_levelsToRegister.Add(level2);
			}
		}

		public static IReadOnlyList<Level> GetLevels()
		{
			if ((Object)(object)RunManager.instance == (Object)null)
			{
				return Array.Empty<Level>();
			}
			return RunManager.instance.levels;
		}

		public static bool TryGetLevelByName(string name, [NotNullWhen(true)] out Level? level)
		{
			level = GetLevelByName(name);
			return (Object)(object)level != (Object)null;
		}

		public static Level? GetLevelByName(string name)
		{
			foreach (Level level in GetLevels())
			{
				if (((Object)level).name.EqualsAny(new <>z__ReadOnlyArray<string>(new string[2]
				{
					name,
					"Level - " + name
				}), StringComparison.OrdinalIgnoreCase))
				{
					return level;
				}
			}
			return null;
		}

		public static bool TryGetLevelThatContainsName(string name, [NotNullWhen(true)] out Level? level)
		{
			level = GetLevelThatContainsName(name);
			return (Object)(object)level != (Object)null;
		}

		public static Level? GetLevelThatContainsName(string name)
		{
			foreach (Level level in GetLevels())
			{
				if (((Object)level).name.Contains(name, StringComparison.OrdinalIgnoreCase))
				{
					return level;
				}
			}
			return null;
		}
	}
	public static class NetworkingEvents
	{
		public static readonly byte[] ReservedEventCodes = new byte[3] { 0, 1, 2 };

		private static readonly List<NetworkedEvent> _customEvents = new List<NetworkedEvent>();

		public static readonly RaiseEventOptions RaiseAll = new RaiseEventOptions
		{
			Receivers = (ReceiverGroup)1
		};

		public static readonly RaiseEventOptions RaiseOthers = new RaiseEventOptions
		{
			Receivers = (ReceiverGroup)0
		};

		public static readonly RaiseEventOptions RaiseMasterClient = new RaiseEventOptions
		{
			Receivers = (ReceiverGroup)2
		};

		public static IReadOnlyList<NetworkedEvent> CustomEvents => _customEvents;

		internal static void Initialize()
		{
			PhotonNetwork.NetworkingClient.EventReceived += OnEvent;
			Application.quitting += delegate
			{
				PhotonNetwork.NetworkingClient.EventReceived -= OnEvent;
			};
		}

		internal static void AddCustomEvent(NetworkedEvent networkedEvent)
		{
			if (!_customEvents.Contains(networkedEvent))
			{
				_customEvents.Add(networkedEvent);
			}
		}

		private static void OnEvent(EventData photonEvent)
		{
			EventData photonEvent2 = photonEvent;
			_customEvents.FirstOrDefault((NetworkedEvent e) => e.EventCode == photonEvent2.Code)?.EventAction?.Invoke(photonEvent2);
		}

		internal static bool TryGetUniqueEventCode(out byte eventCode)
		{
			eventCode = 0;
			while (IsEventCodeTaken(eventCode) && eventCode < 200)
			{
				eventCode++;
			}
			if (eventCode > 200 || (eventCode == 200 && IsEventCodeTaken(eventCode)))
			{
				eventCode = 0;
				return false;
			}
			return true;
		}

		public static bool IsEventCodeTaken(byte eventCode)
		{
			if (ReservedEventCodes.Any((byte x) => x == eventCode))
			{
				return true;
			}
			if (_customEvents.Any((NetworkedEvent x) => x.EventCode == eventCode))
			{
				return true;
			}
			return false;
		}
	}
	public class NetworkedEvent
	{
		public string Name { get; private set; }

		public byte EventCode { get; private set; }

		public Action<EventData> EventAction { get; private set; }

		public NetworkedEvent(string name, Action<EventData> eventAction)
		{
			Name = name;
			EventAction = eventAction;
			if (NetworkingEvents.TryGetUniqueEventCode(out var eventCode))
			{
				EventCode = eventCode;
				NetworkingEvents.AddCustomEvent(this);
				Logger.LogInfo($"Registered NetworkedEvent \"{Name}\" with event code: {EventCode}", extended: true);
			}
			else
			{
				Logger.LogError("Failed to register NetworkedEvent \"" + Name + "\". Could not get unique event code.");
			}
		}

		public void RaiseEvent(object eventContent, RaiseEventOptions raiseEventOptions, SendOptions sendOptions)
		{
			//IL_0018: 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)
			if (SemiFunc.IsMultiplayer())
			{
				PhotonNetwork.RaiseEvent(EventCode, eventContent, raiseEventOptions, sendOptions);
			}
			else if ((int)raiseEventOptions.Receivers != 0)
			{
				RaiseEventSingleplayer(eventContent);
			}
		}

		private void RaiseEventSingleplayer(object eventContent)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			if (!SemiFunc.IsMultiplayer())
			{
				EventData val = new EventData
				{
					Code = EventCode
				};
				val.Parameters[val.CustomDataKey] = eventContent;
				val.Parameters[val.SenderKey] = 1;
				EventAction?.Invoke(val);
			}
		}
	}
	public static class NetworkPrefabs
	{
		private static CustomPrefabPool? _customPrefabPool;

		internal static CustomPrefabPool CustomPrefabPool
		{
			get
			{
				if (_customPrefabPool == null)
				{
					_customPrefabPool = new CustomPrefabPool();
				}
				return _customPrefabPool;
			}
			private set
			{
				_customPrefabPool = value;
			}
		}

		internal static void Initialize()
		{
			if (PhotonNetwork.PrefabPool is CustomPrefabPool)
			{
				Logger.LogWarning("NetworkPrefabs failed to initialize. PhotonNetwork.PrefabPool is already a CustomPrefabPool.");
				return;
			}
			Logger.LogInfo("Initializing NetworkPrefabs.");
			Logger.LogDebug($"PhotonNetwork.PrefabPool = {((object)PhotonNetwork.PrefabPool).GetType()}");
			IPunPrefabPool prefabPool = PhotonNetwork.PrefabPool;
			DefaultPool val = (DefaultPool)(object)((prefabPool is DefaultPool) ? prefabPool : null);
			if (val != null)
			{
				CustomPrefabPool.DefaultPool = val;
			}
			else if (!(PhotonNetwork.PrefabPool is CustomPrefabPool))
			{
				Logger.LogWarning($"PhotonNetwork has an unknown prefab pool assigned. PhotonNetwork.PrefabPool = {((object)PhotonNetwork.PrefabPool).GetType()}");
			}
			PhotonNetwork.PrefabPool = (IPunPrefabPool)(object)CustomPrefabPool;
			Logger.LogInfo("Replaced PhotonNetwork.PrefabPool with CustomPrefabPool.");
			Logger.LogDebug($"PhotonNetwork.PrefabPool = {((object)PhotonNetwork.PrefabPool).GetType()}");
			Logger.LogInfo("Finished initializing NetworkPrefabs.");
		}

		public static void RegisterNetworkPrefab(GameObject prefab)
		{
			RegisterNetworkPrefab((prefab != null) ? ((Object)prefab).name : null, prefab);
		}

		public static void RegisterNetworkPrefab(string prefabId, GameObject prefab)
		{
			CustomPrefabPool.RegisterPrefab(prefabId, prefab);
		}

		public static bool HasNetworkPrefab(string prefabId)
		{
			return CustomPrefabPool.HasPrefab(prefabId);
		}

		public static GameObject? SpawnNetworkPrefab(string prefabId, Vector3 position, Quaternion rotation, byte group = 0, object[]? data = null)
		{
			//IL_0072: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(prefabId))
			{
				Logger.LogError("Failed to spawn network prefab. PrefabId is null.");
				return null;
			}
			if (!HasNetworkPrefab(prefabId))
			{
				Logger.LogError("Failed to spawn network prefab \"" + prefabId + "\". PrefabId is not registered as a network prefab.");
				return null;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				Logger.LogError("Failed to spawn network prefab \"" + prefabId + "\". You are not the host.");
				return null;
			}
			if (SemiFunc.IsMultiplayer())
			{
				return PhotonNetwork.InstantiateRoomObject(prefabId, position, rotation, group, data);
			}
			return Object.Instantiate<GameObject>(CustomPrefabPool.GetPrefab(prefabId), position, rotation);
		}
	}
	public static class ResourcesHelper
	{
		public enum LevelPrefabType
		{
			Module,
			Other,
			StartRoom
		}

		public static string GetValuablesFolderPath(Type volumeType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected I4, but got Unknown
			return "Valuables/" + (int)volumeType switch
			{
				0 => "01 Tiny", 
				1 => "02 Small", 
				2 => "03 Medium", 
				3 => "04 Big", 
				4 => "05 Wide", 
				5 => "06 Tall", 
				6 => "07 Very Tall", 
				_ => string.Empty, 
			};
		}

		public static string GetItemsFolderPath()
		{
			return "Items";
		}

		public static string GetEnemiesFolderPath()
		{
			return "Enemies";
		}

		public static string GetLevelPrefabsFolderPath(Level level, LevelPrefabType type)
		{
			string text = type switch
			{
				LevelPrefabType.Module => "Modules", 
				LevelPrefabType.Other => "Other", 
				LevelPrefabType.StartRoom => "Start Room", 
				_ => string.Empty, 
			};
			return "Level/" + level.ResourcePath + "/" + text;
		}

		public static string GetValuablePrefabPath(ValuableObject valuableObject)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)valuableObject == (Object)null)
			{
				return string.Empty;
			}
			string valuablesFolderPath = GetValuablesFolderPath(valuableObject.volumeType);
			return valuablesFolderPath + "/" + ((Object)((Component)valuableObject).gameObject).name;
		}

		public static string GetValuablePrefabPath(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return string.Empty;
			}
			ValuableObject valuableObject = default(ValuableObject);
			if (prefab.TryGetComponent<ValuableObject>(ref valuableObject))
			{
				return GetValuablePrefabPath(valuableObject);
			}
			return string.Empty;
		}

		public static string GetItemPrefabPath(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return string.Empty;
			}
			return GetItemPrefabPath(item.prefab);
		}

		public static string GetItemPrefabPath(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return string.Empty;
			}
			string itemsFolderPath = GetItemsFolderPath();
			return itemsFolderPath + "/" + ((Object)prefab).name;
		}

		public static string GetEnemyPrefabPath(EnemySetup enemySetup)
		{
			if ((Object)(object)enemySetup == (Object)null || enemySetup.spawnObjects == null)
			{
				return string.Empty;
			}
			GameObject mainSpawnObject = enemySetup.GetMainSpawnObject();
			if ((Object)(object)mainSpawnObject == (Object)null)
			{
				return string.Empty;
			}
			string enemiesFolderPath = GetEnemiesFolderPath();
			return enemiesFolderPath + "/" + ((Object)mainSpawnObject).name;
		}

		public static string GetEnemyPrefabPath(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return string.Empty;
			}
			string enemiesFolderPath = GetEnemiesFolderPath();
			return enemiesFolderPath + "/" + ((Object)prefab).name;
		}

		public static string GetLevelPrefabPath(Level level, GameObject prefab, LevelPrefabType type)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return string.Empty;
			}
			string levelPrefabsFolderPath = GetLevelPrefabsFolderPath(level, type);
			return levelPrefabsFolderPath + "/" + ((Object)prefab).name;
		}

		public static bool HasValuablePrefab(ValuableObject valuableObject)
		{
			if ((Object)(object)valuableObject == (Object)null)
			{
				return false;
			}
			string valuablePrefabPath = GetValuablePrefabPath(valuableObject);
			return (Object)(object)Resources.Load<GameObject>(valuablePrefabPath) != (Object)null;
		}

		public static bool HasItemPrefab(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			string itemPrefabPath = GetItemPrefabPath(item);
			return (Object)(object)Resources.Load<GameObject>(itemPrefabPath) != (Object)null;
		}

		public static bool HasEnemyPrefab(EnemySetup enemySetup)
		{
			if ((Object)(object)enemySetup == (Object)null)
			{
				return false;
			}
			foreach (GameObject distinctSpawnObject in enemySetup.GetDistinctSpawnObjects())
			{
				string enemyPrefabPath = GetEnemyPrefabPath(distinctSpawnObject);
				if ((Object)(object)Resources.Load<GameObject>(enemyPrefabPath) != (Object)null)
				{
					return true;
				}
			}
			return false;
		}

		public static bool HasPrefab(GameObject prefab)
		{
			return (Object)(object)Resources.Load<GameObject>((prefab != null) ? ((Object)prefab).name : null) != (Object)null;
		}

		public static bool HasPrefab(string prefabId)
		{
			return (Object)(object)Resources.Load<GameObject>(prefabId) != (Object)null;
		}
	}
	public static class Utilities
	{
		private static readonly List<GameObject> _prefabsToFix = new List<GameObject>();

		private static readonly List<GameObject> _fixedPrefabs = new List<GameObject>();

		internal static void FixAudioMixerGroupsOnPrefabs()
		{
			foreach (GameObject item in _prefabsToFix)
			{
				item.FixAudioMixerGroups();
				_fixedPrefabs.Add(item);
			}
			_prefabsToFix.Clear();
		}

		public static void FixAudioMixerGroups(GameObject prefab)
		{
			if (!((Object)(object)prefab == (Object)null) && !_prefabsToFix.Contains(prefab) && !_fixedPrefabs.Contains(prefab))
			{
				if ((Object)(object)AudioManager.instance == (Object)null)
				{
					_prefabsToFix.Add(prefab);
					return;
				}
				prefab.FixAudioMixerGroups();
				_fixedPrefabs.Add(prefab);
			}
		}

		internal static void SafeInvokeEvent(Action? action)
		{
			try
			{
				action?.Invoke();
			}
			catch (Exception arg)
			{
				Logger.LogError($"Exception occured while invoking event: {arg}");
			}
		}
	}
	public static class ValuablePresets
	{
		private static readonly Dictionary<string, LevelValuables> _valuablePresets = new Dictionary<string, LevelValuables>();

		public const string GenericValuablePresetName = "Valuables - Generic";

		public static IReadOnlyDictionary<string, LevelValuables> AllValuablePresets => _valuablePresets;

		public static LevelValuables GenericPreset => AllValuablePresets["Valuables - Generic"];

		public static void CacheValuablePresets()
		{
			if ((Object)(object)RunManager.instance == (Object)null)
			{
				Logger.LogError("Failed to cache LevelValuables. RunManager instance is null.");
				return;
			}
			foreach (Level level in RunManager.instance.levels)
			{
				foreach (LevelValuables valuablePreset in level.ValuablePresets)
				{
					_valuablePresets.TryAdd(((Object)valuablePreset).name, valuablePreset);
				}
			}
		}

		internal static void RegisterValuablePreset(LevelValuables valuablePreset)
		{
			_valuablePresets.Add(((Object)valuablePreset).name, valuablePreset);
		}
	}
	public static class Valuables
	{
		private static readonly Dictionary<GameObject, List<string>> _valuablesToRegister = new Dictionary<GameObject, List<string>>();

		private static readonly List<GameObject> _valuablesRegistered = new List<GameObject>();

		private static bool _initialValuablesRegistered;

		public static IReadOnlyList<GameObject> AllValuables => GetValuables();

		public static IReadOnlyList<GameObject> RegisteredValuables => _valuablesRegistered;

		private static IEnumerable<GameObject> PendingAndRegisteredValuables => _valuablesToRegister.Keys.Concat(_valuablesRegistered);

		internal static void RegisterInitialValuables()
		{
			if (_initialValuablesRegistered)
			{
				return;
			}
			Logger.LogInfo("Adding valuables to valuable presets.");
			foreach (GameObject key in _valuablesToRegister.Keys)
			{
				RegisterValuableWithGame(key);
			}
			_valuablesToRegister.Clear();
			_initialValuablesRegistered = true;
		}

		private static void RegisterValuableWithGame(GameObject valuable)
		{
			if (_valuablesRegistered.Contains(valuable))
			{
				return;
			}
			List<string> list = _valuablesToRegister[valuable];
			if (!list.Any((string x) => ValuablePresets.AllValuablePresets.Keys.Any((string y) => x == y)))
			{
				Logger.LogWarning("Valuable \"" + ((Object)valuable).name + "\" does not have any valid valuable preset names set. Adding generic valuable preset name.");
				list.Add("Valuables - Generic");
			}
			foreach (string item in list)
			{
				if (item == null || !ValuablePresets.AllValuablePresets.ContainsKey(item))
				{
					Logger.LogWarning("Failed to add valuable \"" + ((Object)valuable).name + "\" to valuable preset \"" + item + "\". The valuable preset does not exist.");
				}
				else if (ValuablePresets.AllValuablePresets[item].AddValuable(valuable))
				{
					_valuablesRegistered.Add(valuable);
					Logger.LogDebug("Added valuable \"" + ((Object)valuable).name + "\" to valuable preset \"" + item + "\"");
				}
				else
				{
					Logger.LogWarning("Failed to add valuable \"" + ((Object)valuable).name + "\" to valuable preset \"" + item + "\"", extended: true);
				}
			}
		}

		public static void RegisterValuable(GameObject prefab)
		{
			RegisterValuable(prefab, new List<string>());
		}

		public static void RegisterValuable(GameObject prefab, List<LevelValuables> presets)
		{
			RegisterValuable(prefab, presets.Select((LevelValuables preset) => ((Object)preset).name).ToList());
		}

		public static void RegisterValuable(GameObject prefab, List<string> presetNames)
		{
			ValuableObject valuableObject = default(ValuableObject);
			if ((Object)(object)prefab == (Object)null)
			{
				Logger.LogError("Failed to register valuable. Prefab is null.");
			}
			else if (!prefab.TryGetComponent<ValuableObject>(ref valuableObject))
			{
				Logger.LogError("Failed to register valuable. Prefab does not have a ValuableObject component.");
			}
			else
			{
				RegisterValuable(valuableObject, presetNames);
			}
		}

		public static void RegisterValuable(ValuableObject valuableObject)
		{
			RegisterValuable(valuableObject, new List<string>());
		}

		public static void RegisterValuable(ValuableObject valuableObject, List<LevelValuables> presets)
		{
			RegisterValuable(valuableObject, presets.Select((LevelValuables preset) => ((Object)preset).name).ToList());
		}

		public static void RegisterValuable(ValuableObject valuableObject, List<string> presetNames)
		{
			if ((Object)(object)valuableObject == (Object)null)
			{
				Logger.LogError("Failed to register valuable. ValuableObject is null.");
				return;
			}
			GameObject prefab = ((Component)valuableObject).gameObject;
			if (presetNames == null || presetNames.Count == 0)
			{
				Logger.LogWarning("Valuable \"" + ((Object)valuableObject).name + "\" does not have any valid valuable preset names set. Adding generic valuable preset name.", extended: true);
				presetNames = new List<string>(1) { "Valuables - Generic" };
			}
			if (ResourcesHelper.HasValuablePrefab(valuableObject))
			{
				Logger.LogError("Failed to register valuable \"" + ((Object)prefab).name + "\". Valuable prefab already exists in Resources with the same name.");
				return;
			}
			if (PendingAndRegisteredValuables.Any((GameObject x) => ((Object)x).name.Equals(((Object)prefab).name, StringComparison.OrdinalIgnoreCase)))
			{
				Logger.LogError("Failed to register valuable \"" + ((Object)prefab).name + "\". Valuable prefab already exists with the same name.");
				return;
			}
			if (PendingAndRegisteredValuables.Contains(prefab))
			{
				Logger.LogWarning("Failed to register valuable \"" + ((Object)prefab).name + "\". Valuable is already registered!");
				return;
			}
			string valuablePrefabPath = ResourcesHelper.GetValuablePrefabPath(valuableObject);
			NetworkPrefabs.RegisterNetworkPrefab(valuablePrefabPath, prefab);
			Utilities.FixAudioMixerGroups(prefab);
			_valuablesToRegister.Add(prefab, presetNames);
			if (_initialValuablesRegistered)
			{
				RegisterValuableWithGame(((Component)valuableObject).gameObject);
			}
		}

		public static GameObject? SpawnValuable(ValuableObject valuableObject, Vector3 position, Quaternion rotation)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)valuableObject == (Object)null)
			{
				Logger.LogError("Failed to spawn valuable. ValuableObject is null.");
				return null;
			}
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				Logger.LogError("Failed to spawn valuable \"" + ((Object)((Component)valuableObject).gameObject).name + "\". You are not the host.");
				return null;
			}
			string valuablePrefabPath = ResourcesHelper.GetValuablePrefabPath(valuableObject);
			GameObject val = NetworkPrefabs.SpawnNetworkPrefab(valuablePrefabPath, position, rotation, 0);
			if ((Object)(object)val == (Object)null)
			{
				Logger.LogError("Failed to spawn valuable \"" + ((Object)((Component)valuableObject).gameObject).name + "\"");
				return null;
			}
			Logger.LogInfo($"Spawned valuable \"{((Object)val).name}\" at position {position}, rotation: {((Quaternion)(ref rotation)).eulerAngles}", extended: true);
			return val;
		}

		public static IReadOnlyList<GameObject> GetValuables()
		{
			if ((Object)(object)RunManager.instance == (Object)null)
			{
				return Array.Empty<GameObject>();
			}
			return ValuablePresets.AllValuablePresets.Values.Select((LevelValuables levelValuables) => levelValuables.GetCombinedList()).SelectMany((List<GameObject> list) => list).Distinct()
				.ToList();
		}

		public static bool TryGetValuableByName(string name, [NotNullWhen(true)] out ValuableObject? valuableObject)
		{
			valuableObject = GetValuableByName(name);
			return (Object)(object)valuableObject != (Object)null;
		}

		public static ValuableObject? GetValuableByName(string name)
		{
			ValuableObject result = default(ValuableObject);
			foreach (GameObject valuable in GetValuables())
			{
				if (valuable.TryGetComponent<ValuableObject>(ref result) && ((Object)valuable).name.EqualsAny(new <>z__ReadOnlyArray<string>(new string[2]
				{
					name,
					"Valuable " + name
				}), StringComparison.OrdinalIgnoreCase))
				{
					return result;
				}
			}
			return null;
		}

		public static bool TryGetValuableThatContainsName(string name, [NotNullWhen(true)] out ValuableObject? valuableObject)
		{
			valuableObject = GetValuableThatContainsName(name);
			return (Object)(object)valuableObject != (Object)null;
		}

		public static ValuableObject? GetValuableThatContainsName(string name)
		{
			ValuableObject result = default(ValuableObject);
			foreach (GameObject valuable in GetValuables())
			{
				if (valuable.TryGetComponent<ValuableObject>(ref result) && ((Object)valuable).name.Contains(name, StringComparison.OrdinalIgnoreCase))
				{
					return result;
				}
			}
			return null;
		}

		[Obsolete("prefabId is no longer supported", true)]
		public static void RegisterValuable(string prefabId, GameObject prefab)
		{
			RegisterValuable(prefab);
		}

		[Obsolete("prefabId is no longer supported", true)]
		public static void RegisterValuable(string prefabId, GameObject prefab, List<LevelValuables> presets)
		{
			RegisterValuable(prefab, presets);
		}

		[Obsolete("prefabId is no longer supported", true)]
		public static void RegisterValuable(string prefabId, GameObject prefab, List<string> presetNames)
		{
			RegisterValuable(prefab, presetNames);
		}
	}
}
namespace REPOLib.Extensions
{
	public static class AudioSourceExtensions
	{
		public static void FixAudioMixerGroup(this AudioSource audioSource)
		{
			audioSource.FixAudioMixerGroup(((Component)audioSource).gameObject);
		}

		public static void FixAudioMixerGroup(this AudioSource audioSource, GameObject parentObject)
		{
			if ((Object)(object)audioSource == (Object)null)
			{
				return;
			}
			string text = ((!((Object)(object)parentObject == (Object)(object)((Component)audioSource).gameObject)) ? (((Object)parentObject).name + "/" + ((Object)((Component)audioSource).gameObject).name) : ((Object)((Component)audioSource).gameObject).name);
			if ((Object)(object)AudioManager.instance == (Object)null)
			{
				Logger.LogWarning("Failed to fix AudioMixerGroup on GameObject \"" + text + "\". AudioManager instance is null.");
				return;
			}
			if ((Object)(object)audioSource.outputAudioMixerGroup == (Object)null)
			{
				Logger.LogWarning("Failed to fix AudioMixerGroup on GameObject \"" + text + "\". No AudioMixerGroup is assigned.");
				return;
			}
			AudioMixer val = (AudioMixer)(((Object)audioSource.outputAudioMixerGroup.audioMixer).name switch
			{
				"Master" => AudioManager.instance.MasterMixer, 
				"Music" => AudioManager.instance.MusicMasterGroup.audioMixer, 
				"Sound" => AudioManager.instance.SoundMasterGroup.audioMixer, 
				"Spectate" => AudioManager.instance.MicrophoneSpectateGroup.audioMixer, 
				_ => AudioManager.instance.SoundMasterGroup.audioMixer, 
			});
			AudioMixerGroup[] array = val.FindMatchingGroups(((Object)audioSource.outputAudioMixerGroup).name);
			AudioMixerGroup val2;
			if (array.Length >= 1)
			{
				val2 = array[0];
			}
			else
			{
				val = AudioManager.instance.SoundMasterGroup.audioMixer;
				val2 = val.FindMatchingGroups("Sound Effects")[0];
				Logger.LogWarning("Could not find matching AudioMixerGroup for GameObject \"" + text + "\". Using default AudioMixerGroup \"" + ((Object)val).name + "/" + ((Object)val2).name + "\"", extended: true);
			}
			audioSource.outputAudioMixerGroup = val2;
			Logger.LogDebug("Fixed AudioMixerGroup on GameObject \"" + text + "\". AudioMixerGroup \"" + ((Object)val).name + "/" + ((Object)val2).name + "\"");
		}
	}
	public static class DictionaryExtensions
	{
		public static bool TryGetKey<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TValue value, [NotNullWhen(true)] out TKey? key)
		{
			foreach (KeyValuePair<TKey, TValue> item in dictionary)
			{
				if (object.Equals(item.Value, value))
				{
					key = item.Key;
					return true;
				}
			}
			key = default(TKey);
			return false;
		}

		public static TKey? GetKeyOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TValue value)
		{
			if (dictionary.TryGetKey(value, out TKey key))
			{
				return key;
			}
			return default(TKey);
		}

		public static TKey? GetKeyOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TValue value, TKey defaultKey)
		{
			if (dictionary.TryGetKey(value, out TKey key))
			{
				return key;
			}
			return defaultKey;
		}

		public static bool ContainsKey<T>(this Dictionary<string, T> dictionary, string key, bool ignoreKeyCase)
		{
			if (!ignoreKeyCase)
			{
				return dictionary.ContainsKey(key);
			}
			foreach (KeyValuePair<string, T> item in dictionary)
			{
				if (string.Equals(item.Key, key, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		public static bool TryGetValue<T>(this Dictionary<string, T> dictionary, string key, [NotNullWhen(true)] out T? value, bool ignoreKeyCase)
		{
			if (!ignoreKeyCase)
			{
				return dictionary.TryGetValue(key, out value);
			}
			foreach (KeyValuePair<string, T> item in dictionary)
			{
				if (string.Equals(item.Key, key, StringComparison.OrdinalIgnoreCase))
				{
					value = item.Value;
					return true;
				}
			}
			value = default(T);
			return false;
		}

		public static T? GetValueOrDefault<T>(this Dictionary<string, T> dictionary, string key, bool ignoreKeyCase)
		{
			if (dictionary.TryGetValue(key, out T value, ignoreKeyCase))
			{
				return value;
			}
			return default(T);
		}

		public static T? GetValueOrDefault<T>(this Dictionary<string, T> dictionary, string key, T defaultValue, bool ignoreKeyCase)
		{
			if (dictionary.TryGetValue(key, out T value, ignoreKeyCase))
			{
				return value;
			}
			return defaultValue;
		}
	}
	public static class EnemyDirectorExtensions
	{
		public static bool HasEnemy(this EnemyDirector enemyDirector, EnemySetup enemySetup)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)enemySetup == (Object)null || enemySetup.spawnObjects.Count == 0)
			{
				return false;
			}
			EnemyParent val = default(EnemyParent);
			foreach (GameObject spawnObject in enemySetup.spawnObjects)
			{
				if (spawnObject.TryGetComponent<EnemyParent>(ref val) && enemyDirector.TryGetList(val.difficulty, out List<EnemySetup> list))
				{
					return list.Contains(enemySetup);
				}
			}
			return false;
		}

		internal static bool AddEnemy(this EnemyDirector enemyDirector, EnemySetup enemySetup)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)enemySetup == (Object)null)
			{
				return false;
			}
			EnemyParent val = default(EnemyParent);
			foreach (GameObject spawnObject in enemySetup.spawnObjects)
			{
				if (spawnObject.TryGetComponent<EnemyParent>(ref val) && enemyDirector.TryGetList(val.difficulty, out List<EnemySetup> list) && !list.Contains(enemySetup))
				{
					list.Add(enemySetup);
					return true;
				}
			}
			return false;
		}

		public static bool TryGetList(this EnemyDirector enemyDirector, Difficulty difficultyType, [NotNullWhen(true)] out List<EnemySetup>? list)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected I4, but got Unknown
			list = (int)difficultyType switch
			{
				0 => enemyDirector.enemiesDifficulty1, 
				1 => enemyDirector.enemiesDifficulty2, 
				2 => enemyDirector.enemiesDifficulty3, 
				_ => null, 
			};
			return list != null;
		}

		public static List<EnemySetup> GetEnemies(this EnemyDirector enemyDirector)
		{
			List<EnemySetup> enemiesDifficulty = enemyDirector.enemiesDifficulty1;
			List<EnemySetup> enemiesDifficulty2 = enemyDirector.enemiesDifficulty2;
			List<EnemySetup> enemiesDifficulty3 = enemyDirector.enemiesDifficulty3;
			List<EnemySetup> list = new List<EnemySetup>(enemiesDifficulty.Count + enemiesDifficulty2.Count + enemiesDifficulty3.Count);
			list.AddRange(enemiesDifficulty);
			list.AddRange(enemiesDifficulty2);
			list.AddRange(enemiesDifficulty3);
			return list;
		}

		public static bool TryGetEnemyByName(this EnemyDirector enemyDirector, string name, [NotNullWhen(true)] out EnemySetup? enemySetup)
		{
			enemySetup = enemyDirector.GetEnemyByName(name);
			return (Object)(object)enemySetup != (Object)null;
		}

		public static EnemySetup? GetEnemyByName(this EnemyDirector enemyDirector, string name)
		{
			string name2 = name;
			return ((IEnumerable<EnemySetup>)enemyDirector.GetEnemies()).FirstOrDefault((Func<EnemySetup, bool>)((EnemySetup x) => x.NameEquals(name2)));
		}

		public static bool TryGetEnemyThatContainsName(this EnemyDirector enemyDirector, string name, out EnemySetup enemySetup)
		{
			enemySetup = enemyDirector.GetEnemyThatContainsName(name);
			return (Object)(object)enemySetup != (Object)null;
		}

		public static EnemySetup GetEnemyThatContainsName(this EnemyDirector enemyDirector, string name)
		{
			string name2 = name;
			return ((IEnumerable<EnemySetup>)enemyDirector.GetEnemies()).FirstOrDefault((Func<EnemySetup, bool>)((EnemySetup x) => x.NameContains(name2)));
		}
	}
	public static class EnemySetupExtensions
	{
		public static List<GameObject> GetDistinctSpawnObjects(this EnemySetup enemySetup)
		{
			if ((Object)(object)enemySetup == (Object)null || enemySetup.spawnObjects == null)
			{
				return new List<GameObject>();
			}
			return enemySetup.spawnObjects.Where((GameObject x) => (Object)(object)x != (Object)null).Distinct(new UnityObjectNameComparer<GameObject>()).ToList();
		}

		public static List<GameObject> GetSortedSpawnObjects(this EnemySetup enemySetup)
		{
			if ((Object)(object)enemySetup == (Object)null || enemySetup.spawnObjects == null)
			{
				return new List<GameObject>();
			}
			EnemyParent val = default(EnemyParent);
			return (from x in enemySetup.spawnObjects
				where (Object)(object)x != (Object)null
				orderby x.TryGetComponent<EnemyParent>(ref val) descending
				select x).ToList();
		}

		public static GameObject? GetMainSpawnObject(this EnemySetup enemySetup)
		{
			EnemyParent? enemyParent = enemySetup.GetEnemyParent();
			if (enemyParent == null)
			{
				return null;
			}
			return ((Component)enemyParent).gameObject;
		}

		public static EnemyParent? GetEnemyParent(this EnemySetup enemySetup)
		{
			EnemyParent result = default(EnemyParent);
			foreach (GameObject distinctSpawnObject in enemySetup.GetDistinctSpawnObjects())
			{
				if (distinctSpawnObject.TryGetComponent<EnemyParent>(ref result))
				{
					return result;
				}
			}
			return null;
		}

		public static bool TryGetEnemyParent(this EnemySetup enemySetup, [NotNullWhen(true)] out EnemyParent? enemyParent)
		{
			enemyParent = enemySetup.GetEnemyParent();
			return (Object)(object)enemyParent != (Object)null;
		}

		public static bool AnySpawnObjectsNameEquals(this EnemySetup enemySetup, string name)
		{
			string name2 = name;
			if ((Object)(object)enemySetup == (Object)null)
			{
				return false;
			}
			return enemySetup.GetDistinctSpawnObjects().Any((GameObject x) => ((Object)x).name.Equals(name2, StringComparison.OrdinalIgnoreCase));
		}

		public static bool AnySpawnObjectsNameEqualsThatIsNotTheSameObject(this EnemySetup enemySetup, GameObject gameObject)
		{
			GameObject gameObject2 = gameObject;
			if ((Object)(object)enemySetup == (Object)null || (Object)(object)gameObject2 == (Object)null)
			{
				return false;
			}
			return enemySetup.GetDistinctSpawnObjects().Any((GameObject x) => ((Object)x).name.Equals(((Object)gameObject2).name, StringComparison.OrdinalIgnoreCase) && (Object)(object)x != (Object)(object)gameObject2);
		}

		public static bool NameEquals(this EnemySetup enemySetup, string name)
		{
			if ((Object)(object)enemySetup == (Object)null)
			{
				return false;
			}
			if (((Object)enemySetup).name.EqualsAny(new <>z__ReadOnlyArray<string>(new string[2]
			{
				name,
				"Enemy - " + name
			}), StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (enemySetup.TryGetEnemyParent(out EnemyParent enemyParent))
			{
				if (enemyParent.enemyName.Equals(name, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
				if (((Object)((Component)enemyParent).gameObject).name.EqualsAny(new <>z__ReadOnlyArray<string>(new string[2]
				{
					name,
					"Enemy - " + name
				}), StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		public static bool NameContains(this EnemySetup enemySetup, string name)
		{
			if ((Object)(object)enemySetup == (Object)null)
			{
				return false;
			}
			if (((Object)enemySetup).name.Contains(name, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (enemySetup.TryGetEnemyParent(out EnemyParent enemyParent))
			{
				if (enemyParent.enemyName.Contains(name, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
				if (((Object)((Component)enemyParent).gameObject).name.Contains(name, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}
	}
	public static class GameObjectExtensions
	{
		public static void FixAudioMixerGroups(this GameObject gameObject)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return;
			}
			if ((Object)(object)AudioManager.instance == (Object)null)
			{
				Logger.LogWarning("Failed to fix audio mixer groups on GameObject \"" + ((Object)gameObject).name + "\". AudioManager instance is null.");
				return;
			}
			AudioSource[] componentsInChildren = gameObject.GetComponentsInChildren<AudioSource>();
			foreach (AudioSource audioSource in componentsInChildren)
			{
				audioSource.FixAudioMixerGroup(gameObject);
			}
		}
	}
	internal static class ItemExtensions
	{
		public static bool NameEquals(this Item item, string name)
		{
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			if (((Object)item).name.EqualsAny(new <>z__ReadOnlyArray<string>(new string[2]
			{
				name,
				"Item " + name
			}), StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (item.itemAssetName.EqualsAny(new <>z__ReadOnlyArray<string>(new string[2]
			{
				name,
				"Item " + name
			}), StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (item.itemName.Equals(name, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			return false;
		}

		public static bool NameContains(this Item item, string name)
		{
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			if (((Object)item).name.Contains(name, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (item.itemAssetName.Contains(name, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (item.itemName.Contains(name, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			return false;
		}
	}
	public static class LevelValuablesExtensions
	{
		public static bool HasValuable(this LevelValuables levelValuables, GameObject prefab)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			ValuableObject val = default(ValuableObject);
			if (!prefab.TryGetComponent<ValuableObject>(ref val))
			{
				return false;
			}
			if (!levelValuables.TryGetList(val.volumeType, out List<GameObject> list))
			{
				return false;
			}
			return list.Contains(prefab);
		}

		internal static bool AddValuable(this LevelValuables levelValuables, GameObject prefab)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			ValuableObject val = default(ValuableObject);
			if (!prefab.TryGetComponent<ValuableObject>(ref val))
			{
				return false;
			}
			if (!levelValuables.TryGetList(val.volumeType, out List<GameObject> list))
			{
				return false;
			}
			if (list.Contains(prefab))
			{
				return false;
			}
			list.Add(prefab);
			return true;
		}

		public static bool TryGetList(this LevelValuables levelValuables, Type volumeType, [NotNullWhen(true)] out List<GameObject>? list)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected I4, but got Unknown
			list = (int)volumeType switch
			{
				0 => levelValuables.tiny, 
				1 => levelValuables.small, 
				2 => levelValuables.medium, 
				3 => levelValuables.big, 
				4 => levelValuables.wide, 
				5 => levelValuables.tall, 
				6 => levelValuables.veryTall, 
				_ => null, 
			};
			return list != null;
		}

		public static bool TryGetCombinedList(this LevelValuables levelValuables, out List<GameObject> list)
		{
			List<List<GameObject>> source = new List<List<GameObject>> { levelValuables.tiny, levelValuables.small, levelValuables.medium, levelValuables.big, levelValuables.wide, levelValuables.tall, levelValuables.veryTall };
			list = (from x in source.SelectMany((List<GameObject> valuables) => valuables)
				where (Object)(object)x != (Object)null
				select x).Distinct().ToList();
			return list != null;
		}

		public static List<GameObject> GetCombinedList(this LevelValuables levelValuables)
		{
			if (levelValuables.TryGetCombinedList(out List<GameObject> list))
			{
				return list;
			}
			return new List<GameObject>();
		}
	}
	internal static class ReflectionExtensions
	{
		public static IEnumerable<MethodInfo> SafeGetMethods(this Type type)
		{
			try
			{
				return type.GetMethods();
			}
			catch
			{
				return Array.Empty<MethodInfo>();
			}
		}

		public static T? SafeGetCustomAttribute<T>(this MethodInfo method) where T : Attribute
		{
			try
			{
				return method.GetCustomAttribute<T>();
			}
			catch
			{
				return null;
			}
		}

		public static bool HasCustomAttribute<T>(this MethodInfo method) where T : Attribute
		{
			try
			{
				return method.GetCustomAttribute<T>() != null;
			}
			catch
			{
				return false;
			}
		}
	}
	public static class StatsManagerExtensions
	{
		public static bool HasItem(this StatsManager statsManager, Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			return statsManager.itemDictionary.ContainsKey(item.itemAssetName);
		}

		internal static bool AddItem(this StatsManager statsManager, Item item)
		{
			if (!statsManager.itemDictionary.ContainsKey(item.itemAssetName))
			{
				statsManager.itemDictionary.Add(item.itemAssetName, item);
			}
			foreach (Dictionary<string, int> item2 in statsManager.AllDictionariesWithPrefix("item"))
			{
				item2[item.itemAssetName] = 0;
			}
			return true;
		}

		public static List<Item> GetItems(this StatsManager statsManager)
		{
			return statsManager.itemDictionary.Values.ToList();
		}

		public static bool TryGetItemByName(this StatsManager statsManager, string name, out Item item)
		{
			item = statsManager.GetItemByName(name);
			return (Object)(object)item != (Object)null;
		}

		public static Item GetItemByName(this StatsManager statsManager, string name)
		{
			string name2 = name;
			return ((IEnumerable<Item>)statsManager.GetItems()).FirstOrDefault((Func<Item, bool>)((Item x) => x.NameEquals(name2)));
		}

		public static bool TryGetItemThatContainsName(this StatsManager statsManager, string name, out Item item)
		{
			item = statsManager.GetItemThatContainsName(name);
			return (Object)(object)item != (Object)null;
		}

		public static Item GetItemThatContainsName(this StatsManager statsManager, string name)
		{
			string name2 = name;
			return ((IEnumerable<Item>)statsManager.GetItems()).FirstOrDefault((Func<Item, bool>)((Item x) => x.NameContains(name2)));
		}
	}
	public static class StringExtensions
	{
		public static bool EqualsAny(this string value, IReadOnlyCollection<string> inputs, StringComparison comparisonType = StringComparison.Ordinal)
		{
			if (value == null || inputs == null)
			{
				return false;
			}
			return inputs.Contains<string>(value, StringComparer.FromComparison(comparisonType));
		}
	}
}
namespace REPOLib.Commands
{
	[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
	public class CommandExecutionAttribute : Attribute
	{
		public bool RequiresDeveloperMode { get; private set; }

		public bool EnabledByDefault { get; private set; }

		public string Name { get; private set; }

		public string Description { get; private set; }

		public CommandExecutionAttribute(string? name = null, string? description = null, bool enabledByDefault = true, bool requiresDeveloperMode = false)
		{
			RequiresDeveloperMode = requiresDeveloperMode;
			EnabledByDefault = enabledByDefault;
			Name = name ?? "";
			Description = description ?? "";
		}
	}
	[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
	public class CommandInitializerAttribute : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
	public class CommandAliasAttribute : Attribute
	{
		public string Alias { get; private set; }

		public CommandAliasAttribute(string alias)
		{
			Alias = alias;
		}
	}
	internal static class CommandManager
	{
		private static List<MethodInfo> _commandExecutionMethodCache = new List<MethodInfo>();

		public static Dictionary<string, MethodInfo> CommandExecutionMethods { get; private set; } = new Dictionary<string, MethodInfo>();


		public static List<MethodInfo> CommandInitializerMethods { get; private set; } = new List<MethodInfo>();


		public static Dictionary<string, bool> CommandsEnabled { get; private set; } = new Dictionary<string, bool>();


		public static void Initialize()
		{
			Logger.LogInfo("CommandManager initializing.", extended: true);
			CommandInitializerMethods = (from method in AccessTools.AllTypes().SelectMany((Type type) => type.SafeGetMethods())
				where method.HasCustomAttribute<CommandInitializerAttribute>()
				select method).ToList();
			foreach (MethodInfo commandInitializerMethod in CommandInitializerMethods)
			{
				try
				{
					Logger.LogDebug($"Initializing command initializer on method {commandInitializerMethod.DeclaringType}.{commandInitializerMethod.Name}");
					if (!commandInitializerMethod.IsStatic)
					{
						Logger.LogWarning($"Command initializer {commandInitializerMethod.DeclaringType}.{commandInitializerMethod.Name} is not static!");
					}
					commandInitializerMethod.Invoke(null, null);
				}
				catch (Exception arg)
				{
					Logger.LogError($"Failed to initialize command: {arg}");
				}
			}
			FindAllCommandMethods();
			foreach (KeyValuePair<string, MethodInfo> commandExecutionMethod in CommandExecutionMethods)
			{
				if (!commandExecutionMethod.Value.IsStatic)
				{
					Logger.LogWarning("Command execution method for command \"" + commandExecutionMethod.Key + "\" is not static!");
				}
			}
			BindConfigs();
			Logger.LogInfo("Finished initializing custom commands.");
		}

		public static void FindAllCommandMethods()
		{
			_commandExecutionMethodCache = (from method in AccessTools.AllTypes().SelectMany((Type type) => type.SafeGetMethods())
				where method.HasCustomAttribute<CommandExecutionAttribute>()
				select method).ToList();
			foreach (MethodInfo item in _commandExecutionMethodCache)
			{
				ParameterInfo[] parameters = item.GetParameters();
				if (parameters.Length > 1)
				{
					Logger.LogError("Command \"" + item.GetCustomAttribute<CommandExecutionAttribute>().Name + "\" execution method \"" + item.Name + "\" has too many parameters! Should only have 1 string parameter or none.");
					break;
				}
				if (parameters.Length == 1 && parameters[0].ParameterType != typeof(string))
				{
					Logger.LogError("Command \"" + item.GetCustomAttribute<CommandExecutionAttribute>().Name + "\" execution method \"" + item.Name + "\" has parameter of the wrong type! Should be string.");
					break;
				}
				IEnumerable<CommandAliasAttribute> customAttributes = item.GetCustomAttributes<CommandAliasAttribute>();
				bool flag = false;
				if (customAttributes == null || customAttributes.Count() == 0)
				{
					Logger.LogWarning("Command " + item.Name + " has no alias attributes!");
					continue;
				}
				foreach (CommandAliasAttribute item2 in customAttributes)
				{
					if (CommandExecutionMethods.TryAdd(item2.Alias, item))
					{
						Logger.LogDebug($"Registered command alias \"{item2.Alias}\" for method \"{item.DeclaringType}.{item.Name}\".");
						flag = true;
					}
				}
				if (!flag)
				{
					Logger.LogWarning("Failed to add any command aliases for method \"" + item.Name + "\".");
				}
			}
		}

		public static void BindConfigs()
		{
			foreach (MethodInfo item in _commandExecutionMethodCache)
			{
				CommandExecutionAttribute customAttribute = item.GetCustomAttribute<CommandExecutionAttribute>();
				BepInPlugin customAttribute2 = ((MemberInfo)(from type in AccessTools.GetTypesFromAssembly(item.Module.Assembly)
					where ((MemberInfo)type).GetCustomAttribute<BepInPlugin>() != null
					select type).ToList()[0]).GetCustomAttribute<BepInPlugin>();
				string text = ((customAttribute2 != null) ? customAttribute2.GUID : null) ?? "Unknown";
				string text2 = item.DeclaringType.ToString() ?? "Unknown";
				List<string> list = new List<string>();
				foreach (CommandAliasAttribute customAttribute3 in item.GetCustomAttributes<CommandAliasAttribute>())
				{