Decompiled source of TheArchive Essentials v2025.2.0

plugins/TheArchive.Essentials.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using AK;
using Agents;
using AirParticleSystem;
using BepInEx.Unity.IL2CPP.Utils.Collections;
using BoosterImplants;
using CellMenu;
using ChainedPuzzles;
using Clonesoft.Json;
using Clonesoft.Json.Linq;
using Enemies;
using FX_EffectSystem;
using GameData;
using Gear;
using HarmonyLib;
using IRF;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppInterop.Runtime.Runtime;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using LevelGeneration;
using Localization;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using StateMachines;
using Steamworks;
using TMPro;
using TheArchive.Core;
using TheArchive.Core.Attributes;
using TheArchive.Core.Attributes.Feature;
using TheArchive.Core.Attributes.Feature.Members;
using TheArchive.Core.Attributes.Feature.Patches;
using TheArchive.Core.Attributes.Feature.Settings;
using TheArchive.Core.FeaturesAPI;
using TheArchive.Core.FeaturesAPI.Components;
using TheArchive.Core.FeaturesAPI.Settings;
using TheArchive.Core.Localization;
using TheArchive.Core.Managers;
using TheArchive.Core.Models;
using TheArchive.Features.Accessibility;
using TheArchive.Features.Dev;
using TheArchive.Interfaces;
using TheArchive.Loader;
using TheArchive.Utilities;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("2025.2.0")]
[assembly: AssemblyInformationalVersion("2025.2.0")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("TheArchive.Essentials")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyProduct("TheArchive.Essentials")]
[assembly: AssemblyTitle("TheArchive.Essentials")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2025.2.0.0")]
[module: UnverifiableCode]
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;
		}
	}
}
internal class ThisAssembly
{
	public class Git
	{
		public class BaseVersion
		{
			public const string Major = "2025";

			public const string Minor = "2";

			public const string Patch = "0";
		}

		public class SemVer
		{
			public const string Major = "2025";

			public const string Minor = "2";

			public const string Patch = "1";

			public const string Label = "";

			public const string DashLabel = "";

			public const string Source = "Tag";
		}

		public const bool IsDirty = false;

		public const string IsDirtyString = "false";

		public const string RepositoryUrl = "https://github.com/AuriRex/GTFO_TheArchive.git";

		public const string Branch = "main";

		public const string Commit = "6d23fe4";

		public const string Sha = "6d23fe4e8bc046d994648b8c7855588348eff63c";

		public const string CommitDate = "2025-08-23T17:58:53+02:00";

		public const string Commits = "1";

		public const string Tag = "v2025.2.0-1-g6d23fe4";

		public const string BaseTag = "v2025.2.0";
	}
}
internal class ManifestInfo
{
	internal const string TSName = "TheArchive_Essentials";

	internal const string TSDescription = "That one massive GTFO Quality of Life mod.";

	internal const string TSVersion = "2025.2.0";

	internal const string TSAuthor = "AuriRex";

	internal const string TSWebsite = "https://github.com/AuriRex/GTFO_TheArchive";
}
namespace TheArchive
{
	[ArchiveModule("dev.AuriRex.gtfo.TheArchive.Essentials", "TheArchive_Essentials", "2025.2.0")]
	public class ArchiveEssentialsModule : IArchiveModule
	{
		public const string GUID = "dev.AuriRex.gtfo.TheArchive.Essentials";

		public const string MOD_NAME = "TheArchive_Essentials";

		public const string VERSION = "2025.2.0";

		public ILocalizationService LocalizationService { get; set; }

		public IArchiveLogger Logger { get; set; }

		public void Init()
		{
		}
	}
}
namespace TheArchive.Features.Special
{
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	public class AdBlock : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class CM_PageRundown_New_ABC_Patch
		{
			public static void Postfix(CM_PageRundown_New __instance)
			{
				ToggleDOWImage(__instance);
			}
		}

		public override string Name => "AdBlock";

		public override FeatureGroup Group => FeatureGroups.Special;

		public override string Description => "Removes the Den of Wolves button from the rundown screen.";

		public static bool IsEnabled { get; set; }

		public override void OnEnable()
		{
			if (Feature.DataBlocksReady)
			{
				ToggleDOWImage(MainMenuGuiLayer.Current.PageRundownNew);
			}
		}

		public override void OnDisable()
		{
			if (!Feature.IsApplicationQuitting)
			{
				ToggleDOWImage(MainMenuGuiLayer.Current.PageRundownNew, setActive: true);
			}
		}

		private static void ToggleDOWImage(CM_PageRundown_New __instance, bool setActive = false)
		{
			RectTransform movingContentHolder = ((CM_PageBase)__instance).m_movingContentHolder;
			object obj;
			if (movingContentHolder == null)
			{
				obj = null;
			}
			else
			{
				Transform childWithExactName = SharedUtils.GetChildWithExactName((Transform)(object)movingContentHolder, "PasteAndJoinOnLobbyID");
				if (childWithExactName == null)
				{
					obj = null;
				}
				else
				{
					Transform childWithExactName2 = SharedUtils.GetChildWithExactName(childWithExactName, "ButtonGIF");
					obj = ((childWithExactName2 != null) ? ((Component)childWithExactName2).gameObject : null);
				}
			}
			GameObject val = (GameObject)obj;
			if (!((Object)(object)val == (Object)null))
			{
				OnEnabledListener component = val.GetComponent<OnEnabledListener>();
				if ((Object)(object)component != (Object)null && setActive)
				{
					Object.Destroy((Object)(object)component);
				}
				else if ((Object)(object)component == (Object)null)
				{
					component = val.AddComponent<OnEnabledListener>();
					OnEnabledListener obj2 = component;
					obj2.OnEnabledSelf = (Action<GameObject>)Delegate.Combine(obj2.OnEnabledSelf, new Action<GameObject>(OnButtonEnabled));
				}
				val.SetActive(setActive);
			}
		}

		private static void OnButtonEnabled(GameObject go)
		{
			if (IsEnabled)
			{
				go.SetActive(false);
			}
		}
	}
	[EnableFeatureByDefault]
	internal class AltTabCounter : Feature
	{
		public class AltTabCounterSettings
		{
			public class AltTabCounterSettingsForReal
			{
				[FSHeader("ALT + TABs <3", true)]
				[FSReadOnly(true)]
				[FSDisplayName("Total Count")]
				[FSDescription("All time total of ALT + TABs")]
				public int TotalCount { get; set; }

				[FSReadOnly(true)]
				[FSDisplayName("This Session Count")]
				[FSDescription("ALT + TABs accumulated this session")]
				public int CurrentSessionCount { get; set; }

				[FSReadOnly(true)]
				[FSDisplayName("This Level Count")]
				[FSDescription("ALT + TABs accumulated this level")]
				public int CurrentWhileInLevelCount { get; set; }
			}

			[FSUseDynamicSubmenu]
			[FSDisplayName("ALT + TAB Counts")]
			public AltTabCounterSettingsForReal AltTabCounts { get; set; } = new AltTabCounterSettingsForReal();

		}

		public override string Name => "Alt Tab Counter";

		public override FeatureGroup Group => FeatureGroups.Special;

		public override string Description => "Counts the amount of times that the game went out of focus. (ALT + TAB)";

		[FeatureConfig]
		public static AltTabCounterSettings Settings { get; set; }

		public static bool InLevel { get; private set; }

		public override void Init()
		{
			Settings.AltTabCounts.CurrentSessionCount = 0;
		}

		public override void OnApplicationFocusChanged(bool focus)
		{
			if (!focus)
			{
				Settings.AltTabCounts.TotalCount++;
				Settings.AltTabCounts.CurrentSessionCount++;
				if (InLevel)
				{
					Settings.AltTabCounts.CurrentWhileInLevelCount++;
				}
				Feature.MarkSettingsAsDirty<AltTabCounterSettings>(Settings);
			}
		}

		public void OnGameStateChanged(eGameStateName state)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			InLevel = (int)state == 10;
			if (InLevel)
			{
				Settings.AltTabCounts.CurrentWhileInLevelCount = 0;
				Feature.MarkSettingsAsDirty<AltTabCounterSettings>(Settings);
			}
		}
	}
	public class HideFirstPersonItem : Feature
	{
		public class HideFirstPersonItemSettings
		{
			[FSDisplayName("Model Toggle Key")]
			[FSDescription("Key used to toggle the model.")]
			public KeyCode Key { get; set; } = (KeyCode)283;

		}

		public override string Name => "Weapon Model Toggle";

		public override FeatureGroup Group => FeatureGroups.Special;

		public override string Description => "Forces the held item to be hidden.\nIntended for taking pictures.\n<color=orange>(Warning! This makes you unable to use or switch items until unhidden!)</color>";

		[FeatureConfig]
		public static HideFirstPersonItemSettings Settings { get; set; }

		public override void Update()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if ((int)FocusStateManager.CurrentState == 4 && Input.GetKeyDown(Settings.Key))
			{
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				if ((Object)(object)localPlayerAgent != (Object)null && (Object)(object)localPlayerAgent.FPItemHolder != (Object)null)
				{
					localPlayerAgent.FPItemHolder.ForceItemHidden = !localPlayerAgent.FPItemHolder.ForceItemHidden;
				}
			}
		}
	}
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	public class MuteSpeak : Feature
	{
		private static PlayerAgent _localPlayerAgent;

		public override string Name => "Mute Speak";

		public override FeatureGroup Group => FeatureGroups.Special;

		public override string Description => "Binds a few voice lines to keyboard keys.\n\nArrow keys\n[P, L, K, J, H] toggleable by hitting F8; off by default\nHold [Right Control] for alternate lines";

		public static IArchiveLogger FeatureLogger { get; set; }

		public static bool EnableOtherVoiceBinds { get; set; }

		public static void IfKeySay(KeyCode key, uint soundId)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(key))
			{
				PlayerVoiceManager.WantToSay(_localPlayerAgent.CharacterID, soundId);
			}
		}

		public static void IfKeySay(KeyCode key, uint soundId, int characterID)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(key))
			{
				PlayerVoiceManager.WantToSay(characterID, soundId);
			}
		}

		public override void Update()
		{
			if (Input.GetKeyDown((KeyCode)289))
			{
				EnableOtherVoiceBinds = !EnableOtherVoiceBinds;
				FeatureLogger.Notice($"Voice binds enabled: {EnableOtherVoiceBinds}");
			}
			if (PlayerChatManager.InChatMode || SharedUtils.LocalPlayerIsInTerminal || !PlayerManager.TryGetLocalPlayerAgent(ref _localPlayerAgent) || (Object)(object)_localPlayerAgent == (Object)null)
			{
				return;
			}
			if (Input.GetKey((KeyCode)305))
			{
				IfKeySay((KeyCode)303, SoundEventCache.Resolve("PLAY_BIGSPACEENTER01", false));
				IfKeySay((KeyCode)273, SoundEventCache.Resolve("PLAY_CL_NORTH", false));
				IfKeySay((KeyCode)275, SoundEventCache.Resolve("PLAY_CL_EAST", false));
				IfKeySay((KeyCode)274, SoundEventCache.Resolve("PLAY_CL_SOUTH", false));
				IfKeySay((KeyCode)276, SoundEventCache.Resolve("PLAY_CL_WEST", false));
				if (EnableOtherVoiceBinds)
				{
					IfKeySay((KeyCode)112, SoundEventCache.Resolve("PLAY_CL_WELLDONE", false));
					IfKeySay((KeyCode)108, SoundEventCache.Resolve("PLAY_CL_SHH", false));
					IfKeySay((KeyCode)107, SoundEventCache.Resolve("PLAY_CL_WILLDO", false));
					IfKeySay((KeyCode)106, SoundEventCache.Resolve("PLAY_CL_YOUTAKE", false));
					IfKeySay((KeyCode)104, SoundEventCache.Resolve("PLAY_FALLDAMAGEGRUNT02_5A", false), 2);
				}
			}
			else
			{
				IfKeySay((KeyCode)276, SoundEventCache.Resolve("PLAY_CL_LEFT", false));
				IfKeySay((KeyCode)275, SoundEventCache.Resolve("PLAY_CL_RIGHT", false));
				IfKeySay((KeyCode)273, SoundEventCache.Resolve("PLAY_CL_YES", false));
				IfKeySay((KeyCode)274, SoundEventCache.Resolve("PLAY_CL_NO", false));
				if (EnableOtherVoiceBinds)
				{
					IfKeySay((KeyCode)112, SoundEventCache.Resolve("PLAY_CL_SORRY", false));
					IfKeySay((KeyCode)108, SoundEventCache.Resolve("PLAY_CL_HURRY", false));
					IfKeySay((KeyCode)106, SoundEventCache.Resolve("PLAY_CL_THREETWOONEGO", false));
					IfKeySay((KeyCode)107, SoundEventCache.Resolve("PLAY_CL_SYNCHRONIZE", false));
					IfKeySay((KeyCode)104, SoundEventCache.Resolve("PLAY_FALLDAMAGEGRUNT02_5A", false));
				}
			}
		}
	}
	[EnableFeatureByDefault]
	public class ProcessPriority : Feature
	{
		public class ProcessPrioritySettings
		{
			[Localized]
			public enum PriorityClass
			{
				High,
				AboveNormal,
				Normal,
				BelowNormal
			}

			[FSDisplayName("Priority")]
			public PriorityClass Priority { get; set; } = PriorityClass.AboveNormal;

		}

		private static readonly Dictionary<ProcessPrioritySettings.PriorityClass, ProcessPriorityClass> _prioMap = new Dictionary<ProcessPrioritySettings.PriorityClass, ProcessPriorityClass>
		{
			{
				ProcessPrioritySettings.PriorityClass.High,
				ProcessPriorityClass.High
			},
			{
				ProcessPrioritySettings.PriorityClass.AboveNormal,
				ProcessPriorityClass.AboveNormal
			},
			{
				ProcessPrioritySettings.PriorityClass.Normal,
				ProcessPriorityClass.Normal
			},
			{
				ProcessPrioritySettings.PriorityClass.BelowNormal,
				ProcessPriorityClass.BelowNormal
			}
		};

		public override string Name => "Process Priority";

		public override FeatureGroup Group => FeatureGroups.Special;

		public override string Description => $"Set the games process priority.\n\nThis does the same thing as opening up <color=orange>Taskmanager</color>, going into the 'Details' tab and right clicking on GTFO.exe > [Set Priority]\n\nWarning! Your system might lag / stutter while the game is loading if set to <color=orange>{1}</color> or higher!";

		[FeatureConfig]
		public static ProcessPrioritySettings Settings { get; set; }

		public override void OnEnable()
		{
			SetPriority(Settings.Priority);
		}

		public override void OnDisable()
		{
			SetPriority(ProcessPrioritySettings.PriorityClass.Normal);
		}

		public override void OnFeatureSettingChanged(FeatureSetting setting)
		{
			SetPriority(Settings.Priority);
		}

		public void SetPriority(ProcessPrioritySettings.PriorityClass settingsPriority)
		{
			if (_prioMap.TryGetValue(settingsPriority, out var value))
			{
				using (Process process = Process.GetCurrentProcess())
				{
					process.PriorityClass = value;
				}
				((Feature)this).FeatureLogger.Success($"Set ProcessPriority to {settingsPriority}!");
			}
		}
	}
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	public class RemoveChatRestrictions : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class PlayerChatManager_SetupPatch
		{
			public static void Postfix(ref PlayerChatManager __instance)
			{
				try
				{
					SetValues(__instance);
				}
				catch (Exception ex)
				{
					FeatureLogger.Exception(ex);
				}
			}
		}

		private static PropertyAccessor<PlayerChatManager, Il2CppStructArray<int>> A_PlayerChatManager_m_forbiddenChars;

		private readonly int[] _forbiddenChars = new int[3] { 60, 61, 62 };

		public override string Name => "Remove Chat Restrictions";

		public override FeatureGroup Group => FeatureGroups.Special;

		public override string Description => "Allows the usage of '>' and '<' characters in chat.\n\n(Also enables TextMeshPro RichText tags to be used in chat, don't do stupid things!)";

		public static IArchiveLogger FeatureLogger { get; set; }

		public override void OnEnable()
		{
			SetValues(PlayerChatManager.Current);
		}

		public override void OnDisable()
		{
			SetValues(PlayerChatManager.Current, _forbiddenChars);
		}

		public override void Init()
		{
			A_PlayerChatManager_m_forbiddenChars = PropertyAccessor<PlayerChatManager, Il2CppStructArray<int>>.GetAccessor("m_forbiddenChars", false);
		}

		public static void SetValues(PlayerChatManager instance, int[] values = null)
		{
			if (!((Object)(object)instance == (Object)null))
			{
				A_PlayerChatManager_m_forbiddenChars.Set(instance, Il2CppStructArray<int>.op_Implicit(values ?? Array.Empty<int>()));
			}
		}
	}
}
namespace TheArchive.Features.Security
{
	[EnableFeatureByDefault]
	public class AntiBoosterHack : Feature
	{
		public class AntiBoosterHackSettings
		{
			[Localized]
			public enum PunishmentMode
			{
				NoneAndLog,
				Kick,
				KickAndBan
			}

			[FSDisplayName("Punish Friends")]
			[FSDescription("If (Steam) Friends should be affected as well.")]
			public bool PunishFriends { get; set; }

			[FSDisplayName("Punishment")]
			[FSDescription("What to do with griefers that are using modified boosters.")]
			public PunishmentMode Punishment { get; set; } = PunishmentMode.Kick;

		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		private class BoosterImplantManager__OnSyncBoosterImplants__Patch
		{
			private static void Postfix(SNet_Player player, pBoosterImplantsWithOwner pBoosterImplantsWithOwner)
			{
				SNet_Player player2 = default(SNet_Player);
				if (SNet.IsMaster && pBoosterImplantsWithOwner != null && (player == null || !player.IsLocal) && SNet.Replication.TryGetLastSender(ref player2, false) && ((pBoosterImplantsWithOwner.BasicImplant.BoosterEffectCount != 0 && !BoosterImplantTemplateManager.TryGetBoosterImplantTemplate(pBoosterImplantsWithOwner.BasicImplant, (BoosterImplantCategory)0)) || (pBoosterImplantsWithOwner.AdvancedImplant.BoosterEffectCount != 0 && !BoosterImplantTemplateManager.TryGetBoosterImplantTemplate(pBoosterImplantsWithOwner.AdvancedImplant, (BoosterImplantCategory)1)) || (pBoosterImplantsWithOwner.SpecializedImplant.BoosterEffectCount != 0 && !BoosterImplantTemplateManager.TryGetBoosterImplantTemplate(pBoosterImplantsWithOwner.SpecializedImplant, (BoosterImplantCategory)2))))
				{
					PunishPlayer(player2);
				}
			}
		}

		public static class BoosterImplantTemplateManager
		{
			public class LocalizedTextJsonConverter : JsonConverter
			{
				public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
				{
					writer.WriteValue(string.Empty);
				}

				public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
				{
					return BoosterImplantTemplateDataBlock.UNKNOWN_BLOCK.PublicName;
				}

				public override bool CanConvert(Type objectType)
				{
					return objectType == typeof(LocalizedText);
				}
			}

			public class ListOfTConverter<T> : JsonConverter<List<T>>
			{
				public override List<T> ReadJson(JsonReader reader, Type objectType, List<T> existingValue, bool hasExistingValue, JsonSerializer serializer)
				{
					//IL_0008: Unknown result type (might be due to invalid IL or missing references)
					//IL_000e: Invalid comparison between Unknown and I4
					JToken val = JToken.Load(reader);
					if ((int)val.Type == 2)
					{
						return SharedUtils.ToIL2CPPListIfNecessary<T>(val.ToObject<List<T>>(serializer));
					}
					return null;
				}

				public override void WriteJson(JsonWriter writer, List<T> value, JsonSerializer serializer)
				{
					JToken.FromObject((object)value).WriteTo(writer, Array.Empty<JsonConverter>());
				}

				public ListOfTConverter()
				{
					((JsonConverter<List<List<T>>>)(object)this)..ctor();
				}
			}

			public class ListOfListOfTConverter<T> : JsonConverter<List<List<T>>>
			{
				public override List<List<T>> ReadJson(JsonReader reader, Type objectType, List<List<T>> existingValue, bool hasExistingValue, JsonSerializer serializer)
				{
					//IL_000e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0014: Invalid comparison between Unknown and I4
					//IL_001a: Unknown result type (might be due to invalid IL or missing references)
					//IL_001f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0034: Unknown result type (might be due to invalid IL or missing references)
					//IL_003a: Invalid comparison between Unknown and I4
					//IL_0045: Unknown result type (might be due to invalid IL or missing references)
					//IL_004a: Unknown result type (might be due to invalid IL or missing references)
					JToken val = JToken.Load(reader);
					List<List<T>> val2 = (List<List<T>>)(object)new List<List<List<T>>>();
					if ((int)val.Type == 2)
					{
						foreach (JToken item in val.Children())
						{
							if ((int)item.Type != 2)
							{
								continue;
							}
							List<T> val3 = new List<T>();
							foreach (JToken item2 in item.Children())
							{
								T val4 = item2.ToObject<T>(serializer);
								val3.Add(val4);
							}
							((List<List<List<T>>>)(object)val2).Add((List<List<T>>)(object)val3);
						}
					}
					return val2;
				}

				public override void WriteJson(JsonWriter writer, List<List<T>> value, JsonSerializer serializer)
				{
					JToken.FromObject((object)value).WriteTo(writer, Array.Empty<JsonConverter>());
				}

				public ListOfListOfTConverter()
				{
					((JsonConverter<List<List<List<List<T>>>>>)(object)this)..ctor();
				}
			}

			public class BoosterImplantEffectTemplate
			{
				public uint BoosterImplantEffect { get; set; }

				public float EffectMaxValue { get; set; }

				public float EffectMinValue { get; set; }

				public BoosterImplantEffectTemplate(BoosterImplantEffectInstance effect)
				{
					EffectMaxValue = effect.MaxValue;
					EffectMinValue = effect.MinValue;
					BoosterImplantEffect = effect.BoosterImplantEffect;
				}
			}

			public class BoosterImplantTemplate
			{
				public uint BoosterImplantID { get; set; }

				public BoosterImplantCategory ImplantCategory { get; set; }

				[JsonIgnore]
				public List<BoosterImplantEffectTemplate> Effects { get; set; } = new List<BoosterImplantEffectTemplate>();


				[JsonIgnore]
				public List<List<BoosterImplantEffectTemplate>> RandomEffects { get; set; } = new List<List<BoosterImplantEffectTemplate>>();


				[JsonIgnore]
				public List<uint> Conditions { get; set; } = new List<uint>();


				[JsonIgnore]
				public List<uint> RandomConditions { get; set; } = new List<uint>();


				[JsonIgnore]
				public BoosterImplantTemplateDataBlock TemplateDataBlock { get; private set; }

				public List<List<BoosterImplantEffectTemplate>> EffectGroups { get; set; } = new List<List<BoosterImplantEffectTemplate>>();


				public List<List<uint>> ConditionGroups { get; set; } = new List<List<uint>>();


				public BoosterImplantTemplate(BoosterImplantTemplateDataBlock block)
				{
					//IL_005d: Unknown result type (might be due to invalid IL or missing references)
					TemplateDataBlock = block;
					BoosterImplantID = ((GameDataBlockBase<BoosterImplantTemplateDataBlock>)(object)block).persistentID;
					ImplantCategory = block.ImplantCategory;
					for (int i = 0; i < block.Effects.Count; i++)
					{
						Effects.Add(new BoosterImplantEffectTemplate(block.Effects[i]));
					}
					for (int j = 0; j < block.RandomEffects.Count; j++)
					{
						List<BoosterImplantEffectTemplate> list = new List<BoosterImplantEffectTemplate>();
						for (int k = 0; k < block.RandomEffects[j].Count; k++)
						{
							list.Add(new BoosterImplantEffectTemplate(block.RandomEffects[j][k]));
						}
						RandomEffects.Add(list);
					}
					Conditions.AddRange((IEnumerable<uint>)block.Conditions.ToArray());
					RandomConditions.AddRange((IEnumerable<uint>)block.RandomConditions.ToArray());
					EffectGroups = GenerateEffectGroups();
					ConditionGroups = GenerateConditionGroups();
				}

				private List<List<BoosterImplantEffectTemplate>> GenerateEffectGroups()
				{
					List<List<BoosterImplantEffectTemplate>> list = new List<List<BoosterImplantEffectTemplate>>();
					List<List<BoosterImplantEffectTemplate>> nElementCombinations = GetNElementCombinations(RandomEffects);
					for (int i = 0; i < nElementCombinations.Count; i++)
					{
						List<BoosterImplantEffectTemplate> list2 = Effects.ToList();
						list2.AddRange(nElementCombinations[i]);
						list.Add(list2);
					}
					return list;
				}

				private List<List<uint>> GenerateConditionGroups()
				{
					return GetNElementCombinations(new List<List<uint>> { Conditions, RandomConditions });
				}
			}

			private static string _r5BoosterTemplatesJson;

			private static List<BoosterImplantTemplateDataBlock> OldBoosterImplantTemplateDataBlocks = new List<BoosterImplantTemplateDataBlock>();

			public static List<BoosterImplantTemplate> BoosterImplantTemplates { get; } = new List<BoosterImplantTemplate>();


			private static string R5BoosterTemplatesJson
			{
				get
				{
					if (!string.IsNullOrWhiteSpace(_r5BoosterTemplatesJson))
					{
						return _r5BoosterTemplatesJson;
					}
					byte[] bytes = Utils.LoadFromResource("TheArchive.Resources.RundownFiveBoosterTemplates.json");
					_r5BoosterTemplatesJson = Encoding.UTF8.GetString(bytes);
					return _r5BoosterTemplatesJson;
				}
			}

			public static void LoadTemplateData()
			{
				OldBoosterImplantTemplateDataBlocks.Clear();
				OldBoosterImplantTemplateDataBlocks.AddRange(JsonConvert.DeserializeObject<List<BoosterImplantTemplateDataBlock>>(R5BoosterTemplatesJson, (JsonConverter[])(object)new JsonConverter[4]
				{
					new LocalizedTextJsonConverter(),
					(JsonConverter)new ListOfTConverter<uint>(),
					(JsonConverter)new ListOfTConverter<BoosterImplantEffectInstance>(),
					(JsonConverter)new ListOfListOfTConverter<BoosterImplantEffectInstance>()
				}));
				BoosterImplantTemplates.Clear();
				Il2CppArrayBase<BoosterImplantTemplateDataBlock> allBlocksForEditor = GameDataBlockBase<BoosterImplantTemplateDataBlock>.GetAllBlocksForEditor();
				for (int i = 0; i < allBlocksForEditor.Count; i++)
				{
					BoosterImplantTemplates.Add(new BoosterImplantTemplate(allBlocksForEditor[i]));
				}
				for (int j = 0; j < OldBoosterImplantTemplateDataBlocks.Count; j++)
				{
					BoosterImplantTemplates.Add(new BoosterImplantTemplate(OldBoosterImplantTemplateDataBlocks[j]));
				}
			}

			public static bool TryGetBoosterImplantTemplate(pBoosterImplantData boosterImplant, BoosterImplantCategory category)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
				if (boosterImplant == null)
				{
					return false;
				}
				uint persistenID = boosterImplant.BoosterImplantID;
				List<BoosterImplantTemplate> list = BoosterImplantTemplates.FindAll((BoosterImplantTemplate p) => p.BoosterImplantID == persistenID && p.ImplantCategory == category);
				for (int k = 0; k < list.Count; k++)
				{
					BoosterImplantTemplate boosterImplantTemplate = list[k];
					if (boosterImplantTemplate == null || boosterImplantTemplate.TemplateDataBlock == null)
					{
						continue;
					}
					List<List<uint>> conditionGroups = boosterImplantTemplate.ConditionGroups;
					int conditionCount = boosterImplant.ConditionCount;
					bool flag = false;
					IEnumerable<uint> conditions = ((IEnumerable<uint>)boosterImplant.Conditions).Take(conditionCount);
					int j;
					for (j = 0; j < conditionGroups.Count; j++)
					{
						if (conditionCount != conditionGroups[j].Count)
						{
							continue;
						}
						bool num = conditions.All((uint p) => conditionGroups[j].Any((uint q) => q == p));
						bool flag2 = conditionGroups[j].All((uint p) => conditions.Any((uint q) => q == p));
						if (num && flag2)
						{
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						continue;
					}
					int boosterEffectCount = boosterImplant.BoosterEffectCount;
					bool flag3 = false;
					List<List<BoosterImplantEffectTemplate>> effectGroups = boosterImplantTemplate.EffectGroups;
					IEnumerable<pBoosterEffectData> effects = ((IEnumerable<pBoosterEffectData>)boosterImplant.BoosterEffectDatas).Take(boosterEffectCount);
					int i;
					for (i = 0; i < effectGroups.Count; i++)
					{
						if (effectGroups[i].Count != boosterEffectCount)
						{
							continue;
						}
						for (int l = 0; l < effectGroups[i].Count; l++)
						{
							bool num2 = effects.All((pBoosterEffectData p) => effectGroups[i].Any((BoosterImplantEffectTemplate q) => q.BoosterImplantEffect == p.BoosterEffectID && p.EffectValue >= q.EffectMinValue && p.EffectValue <= q.EffectMaxValue));
							bool flag4 = effectGroups[i].All((BoosterImplantEffectTemplate p) => effects.Any((pBoosterEffectData q) => q.BoosterEffectID == p.BoosterImplantEffect && q.EffectValue >= p.EffectMinValue && q.EffectValue <= p.EffectMaxValue));
							if (num2 && flag4)
							{
								flag3 = true;
								break;
							}
						}
						if (flag3)
						{
							break;
						}
					}
					if (flag3)
					{
						bool flag5 = boosterImplant.UseCount <= (int)boosterImplantTemplate.TemplateDataBlock.DurationRange.y && boosterImplant.UseCount >= 0;
						if (flag && flag3 && flag5)
						{
							return true;
						}
					}
				}
				return false;
			}

			private static List<List<T>> GetNElementCombinations<T>(List<List<T>> lists)
			{
				List<List<T>> list = new List<List<T>>();
				GetNElementCombinationsHelper(lists, new List<T>(), 0, list);
				return list;
			}

			private static void GetNElementCombinationsHelper<T>(List<List<T>> lists, List<T> currentCombination, int currentIndex, List<List<T>> combinations)
			{
				if (currentIndex == lists.Count)
				{
					combinations.Add(new List<T>(currentCombination));
					return;
				}
				List<T> list = lists[currentIndex];
				if (list.Count == 0)
				{
					GetNElementCombinationsHelper(lists, currentCombination, currentIndex + 1, combinations);
					return;
				}
				foreach (T item in list)
				{
					currentCombination.Add(item);
					GetNElementCombinationsHelper(lists, currentCombination, currentIndex + 1, combinations);
					currentCombination.RemoveAt(currentCombination.Count - 1);
				}
			}
		}

		public override string Name => "Anti Booster Hack";

		public override string Description => "Prevents clients from using modified boosters.";

		public override FeatureGroup Group => FeatureGroups.Security;

		public static IArchiveLogger FeatureLogger { get; set; }

		[FeatureConfig]
		public static AntiBoosterHackSettings Settings { get; set; }

		public override void Init()
		{
			if (ArchiveMod.IsPlayingModded)
			{
				((Feature)this).RequestDisable("Playing Modded");
			}
		}

		public override void OnGameDataInitialized()
		{
			BoosterImplantTemplateManager.LoadTemplateData();
		}

		public static bool PunishPlayer(SNet_Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return true;
			}
			if (SharedUtils.IsFriend(player) && !Settings.PunishFriends)
			{
				FeatureLogger.Notice($"Friend \"{player.NickName}\" \"{player.Lookup}\" is using modified boosters!");
				return false;
			}
			switch (Settings.Punishment)
			{
			case AntiBoosterHackSettings.PunishmentMode.KickAndBan:
				PlayerLobbyManagement.BanPlayer(player);
				break;
			case AntiBoosterHackSettings.PunishmentMode.Kick:
				PlayerLobbyManagement.KickPlayer(player);
				break;
			}
			FeatureLogger.Notice($"Player \"{player.NickName}\" \"{player.Lookup}\" is using modified boosters! ({Settings.Punishment})");
			return true;
		}
	}
	[EnableFeatureByDefault]
	public class AntiGearHack : Feature
	{
		public class AntiGearHackSettings
		{
			[Localized]
			public enum PunishmentMode
			{
				NoneAndLog,
				Kick,
				KickAndBan
			}

			[FSDisplayName("Punish Friends")]
			[FSDescription("If (Steam) Friends should be affected as well.")]
			public bool PunishFriends { get; set; }

			[FSDisplayName("Punishment")]
			[FSDescription("What to do with griefers that are using modified gears.")]
			public PunishmentMode Punishment { get; set; } = PunishmentMode.Kick;

		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		private class PlayerBackpackManager__ReceiveInventorySync__Patch
		{
			private static void Prefix(pInventorySync data)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_005f: Expected O, but got Unknown
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Expected O, but got Unknown
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Expected O, but got Unknown
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				//IL_0092: Expected O, but got Unknown
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a3: Expected O, but got Unknown
				if (!SNet.IsMaster)
				{
					return;
				}
				pPlayer sourcePlayer = data.sourcePlayer;
				SNet_Player val = default(SNet_Player);
				SNet_Player val2 = default(SNet_Player);
				if (!((pPlayer)(ref sourcePlayer)).TryGetPlayer(ref val) || val.IsLocal || val.IsBot || !SNet.Replication.TryGetLastSender(ref val2, false) || val2.IsLocal || val2.IsBot)
				{
					return;
				}
				foreach (GearIDRange item in new List<GearIDRange>
				{
					new GearIDRange(data.gearStandard),
					new GearIDRange(data.gearSpecial),
					new GearIDRange(data.gearMelee),
					new GearIDRange(data.gearClass),
					new GearIDRange(data.gearHacking)
				})
				{
					if (!CheckGearIDRange(item))
					{
						PunishPlayer(val2);
						break;
					}
				}
			}
		}

		private static Dictionary<string, string> GearCompsHashLookup = new Dictionary<string, string>();

		public override string Name => "Anti Gear Hack";

		public override string Description => "Prevents clients from using modified gear.";

		public override FeatureGroup Group => FeatureGroups.Security;

		public static IArchiveLogger FeatureLogger { get; set; }

		[FeatureConfig]
		public static AntiGearHackSettings Settings { get; set; }

		public override void Init()
		{
			if (ArchiveMod.IsPlayingModded)
			{
				((Feature)this).RequestDisable("Playing Modded");
			}
		}

		public override void OnGameDataInitialized()
		{
			LoadData();
		}

		public static bool PunishPlayer(SNet_Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return true;
			}
			if (SharedUtils.IsFriend(player) && !Settings.PunishFriends)
			{
				FeatureLogger.Notice($"Friend \"{player.NickName}\" \"{player.Lookup}\" is using modified gears!");
				return false;
			}
			switch (Settings.Punishment)
			{
			case AntiGearHackSettings.PunishmentMode.KickAndBan:
				PlayerLobbyManagement.BanPlayer(player);
				break;
			case AntiGearHackSettings.PunishmentMode.Kick:
				PlayerLobbyManagement.KickPlayer(player);
				break;
			}
			FeatureLogger.Notice($"Player \"{player.NickName}\" \"{player.Lookup}\" is using modified gears! ({Settings.Punishment})");
			return true;
		}

		public static bool CheckIsValidWeaponGearIDRangeDataForPlayer(SNet_Player player)
		{
			if (!player.HasCharacterSlot)
			{
				return false;
			}
			Enumerator<GearIDRange> enumerator = ((Il2CppArrayBase<List<GearIDRange>>)(object)GearManager.Current.m_gearPerSlot)[player.PlayerSlotIndex()].GetEnumerator();
			while (enumerator.MoveNext())
			{
				if (CheckGearIDRange(enumerator.Current))
				{
					return false;
				}
			}
			return true;
		}

		public static bool CheckGearIDRange(GearIDRange gearIDRange)
		{
			string input = gearIDRange.ToJSON();
			string pattern = "(?<=Comps\":)(.*?)(?=,\"MatTrans\")";
			string key = Utils.HashString(Regex.Match(input, pattern).Value);
			return GearCompsHashLookup.ContainsKey(key);
		}

		public static void LoadData()
		{
			GearCompsHashLookup.Clear();
			foreach (PlayerOfflineGearDataBlock allBlock in GameDataBlockBase<PlayerOfflineGearDataBlock>.GetAllBlocks())
			{
				string gearJSON = allBlock.GearJSON;
				string pattern = "(?<=Comps\":)(.*?)(?=,\"MatTrans\")";
				string key = Utils.HashString(Regex.Match(gearJSON, pattern).Value);
				GearCompsHashLookup[key] = gearJSON;
			}
		}
	}
	[EnableFeatureByDefault]
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	public class AntiSpawn : Feature
	{
		public class AntiSpawnSettings
		{
			[Localized]
			public enum PunishmentMode
			{
				NoneAndLog,
				Kick,
				KickAndBan
			}

			[FSDisplayName("Punish Friends")]
			[FSDescription("If (Steam) Friends should be affected as well.")]
			public bool PunishFriends { get; set; }

			[FSDisplayName("Punishment")]
			[FSDescription("What to do with griefers that are trying to spawn in enemies.")]
			public PunishmentMode Punishment { get; set; } = PunishmentMode.Kick;

		}

		public unsafe delegate void Original_InternalSpawnRequestFromSlaveCallback(IntPtr self, IntPtr spawnData, Il2CppMethodInfo* methodInfo);

		private static bool _hasBeenPatched = false;

		private static Original_InternalSpawnRequestFromSlaveCallback _originalMethod_InternalSpawnRequestFromSlaveCallback_pEnemySpawnData;

		private unsafe static Original_InternalSpawnRequestFromSlaveCallback _detourMethod_InternalSpawnRequestFromSlaveCallback_pEnemySpawnData = InternalSpawnRequestFromSlaveCallback_pEnemySpawnData_Replacement;

		private static Original_InternalSpawnRequestFromSlaveCallback _originalMethod_InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData;

		private unsafe static Original_InternalSpawnRequestFromSlaveCallback _detourMethod_InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData = InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData_Replacement;

		public override string Name => "Anti Spawn";

		public override FeatureGroup Group => FeatureGroups.Security;

		public override string Description => "Prevents clients from spawning in enemies.";

		public static IArchiveLogger FeatureLogger { get; set; }

		public static bool IsEnabled { get; set; }

		[FeatureConfig]
		public static AntiSpawnSettings Settings { get; set; }

		public override void OnEnable()
		{
			OneTimePatch();
		}

		private static void OneTimePatch()
		{
			if (!_hasBeenPatched)
			{
				LoaderWrapper.ApplyNativeHook<SNet_ReplicationManager<pEnemySpawnData, EnemyReplicator>, Original_InternalSpawnRequestFromSlaveCallback>("InternalSpawnRequestFromSlaveCallback", typeof(void).FullName, new string[1] { typeof(pEnemySpawnData).FullName }, _detourMethod_InternalSpawnRequestFromSlaveCallback_pEnemySpawnData, ref _originalMethod_InternalSpawnRequestFromSlaveCallback_pEnemySpawnData);
				LoaderWrapper.ApplyNativeHook<SNet_ReplicationManager<pEnemyGroupSpawnData, SNet_DynamicReplicator<pEnemyGroupSpawnData>>, Original_InternalSpawnRequestFromSlaveCallback>("InternalSpawnRequestFromSlaveCallback", typeof(void).FullName, new string[1] { typeof(pEnemyGroupSpawnData).FullName }, _detourMethod_InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData, ref _originalMethod_InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData);
				_hasBeenPatched = true;
			}
		}

		public unsafe static void InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData_Replacement(IntPtr self, IntPtr spawnData, Il2CppMethodInfo* methodInfo)
		{
			if (IsEnabled && SNet.IsMaster && !SNet.Capture.IsCheckpointRecall)
			{
				bool flag = true;
				SNet_Player player = default(SNet_Player);
				if (SNet.Replication.TryGetLastSender(ref player, false))
				{
					flag = PunishPlayer(player);
				}
				if (flag)
				{
					FeatureLogger.Fail("Cancelled enemy spawn!");
					return;
				}
			}
			_originalMethod_InternalSpawnRequestFromSlaveCallback_pEnemyGroupSpawnData(self, spawnData, methodInfo);
		}

		public unsafe static void InternalSpawnRequestFromSlaveCallback_pEnemySpawnData_Replacement(IntPtr self, IntPtr spawnData, Il2CppMethodInfo* methodInfo)
		{
			if (IsEnabled && SNet.IsMaster && !SNet.Capture.IsCheckpointRecall)
			{
				bool flag = true;
				SNet_Player player = default(SNet_Player);
				if (SNet.Replication.TryGetLastSender(ref player, false))
				{
					flag = PunishPlayer(player);
				}
				if (flag)
				{
					FeatureLogger.Fail("Cancelled enemy spawn!");
					return;
				}
			}
			_originalMethod_InternalSpawnRequestFromSlaveCallback_pEnemySpawnData(self, spawnData, methodInfo);
		}

		public static bool PunishPlayer(SNet_Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return true;
			}
			if (SharedUtils.IsFriend(player) && !Settings.PunishFriends)
			{
				FeatureLogger.Notice("Friend \"" + player.NickName + "\" is spawning something in!");
				return false;
			}
			switch (Settings.Punishment)
			{
			case AntiSpawnSettings.PunishmentMode.KickAndBan:
				PlayerLobbyManagement.BanPlayer(player);
				break;
			case AntiSpawnSettings.PunishmentMode.Kick:
				PlayerLobbyManagement.KickPlayer(player);
				break;
			}
			FeatureLogger.Notice($"Player \"{player.NickName}\" tried to spawn something! ({Settings.Punishment})");
			return true;
		}
	}
	[EnableFeatureByDefault]
	public class PlayerLobbyManagement : Feature
	{
		public class LobbyManagementSettings
		{
			public class LobbyColorSettings
			{
				[FSDisplayName("Color the Square")]
				[FSDescription("Use the colors/settings below to color the square on the loadout screen next to the player names.")]
				public bool ColorizeLobbyBullet { get; set; } = true;


				[FSDisplayName("Use Nickname Color for Self")]
				public bool UseNicknameColorForSelf { get; set; } = true;


				[FSDisplayName("Random Colors for Self")]
				public bool RainbowPukeSelf { get; set; }

				[FSDisplayName("Random Colors for Others")]
				public bool RainbowPukeFriends { get; set; }

				[FSHeader("Colors", true)]
				[FSDisplayName("Default")]
				public SColor Default { get; set; } = new SColor(1f, 1f, 1f, (float?)null);


				[FSDisplayName("Friends")]
				public SColor Friends { get; set; } = new SColor(0.964f, 0.921f, 0.227f, (float?)null);


				[FSDisplayName("Bots")]
				public SColor Bots { get; set; } = new SColor(0.949f, 0.58f, 0f, (float?)null);


				[FSDisplayName("Banned")]
				public SColor Banned { get; set; } = new SColor(0.545f, 0f, 0f, (float?)null);


				[FSDisplayName("Self")]
				public SColor Self { get; set; } = new SColor(1f, 1f, 1f, (float?)null);

			}

			public class BanListEntry
			{
				[FSSeparator]
				[FSReadOnly(true)]
				[FSDisplayName("Name")]
				public string Name { get; set; }

				[FSReadOnly(true)]
				[FSDisplayName("SteamID")]
				public ulong SteamID { get; set; }

				[FSReadOnly(true)]
				[FSTimestamp("U")]
				[FSDisplayName("Banned on:")]
				public long Timestamp { get; set; }
			}

			public class RecentlyPlayedWithEntry
			{
				[FSSeparator]
				[FSReadOnly(true)]
				[FSDisplayName("Name")]
				public string Name { get; set; }

				[FSReadOnly(true)]
				[FSDisplayName("SteamID")]
				public ulong SteamID { get; set; }

				[FSReadOnly(true)]
				[FSTimestamp("U")]
				[FSDisplayName("First time played with:")]
				public long TimestampFirst { get; set; }

				[FSReadOnly(true)]
				[FSTimestamp("U")]
				[FSDisplayName("Last time played with:")]
				public long TimestampLast { get; set; }
			}

			[FSDisplayName("Names on Map open Steam Profile")]
			[FSDescription("If clicking a players name on the map screen should open their Steam Profile in your default browser.")]
			public bool NamesOnMapOpenSteamProfile { get; set; }

			[FSDisplayName("Open Profiles in Steam Overlay")]
			[FSDescription("Wheter to open profile links in the overlay or in the default OS browser.")]
			public bool PreferOpeningProfileLinksInSteamOverlay { get; set; } = true;


			[FSHeader("Lobby Color Settings", true)]
			[FSDisplayName("Lobby Colors")]
			public LobbyColorSettings LobbyColors { get; set; } = new LobbyColorSettings();


			[FSHeader("Other", true)]
			[FSDisplayName("Recently Played With")]
			public List<RecentlyPlayedWithEntry> RecentlyPlayedWith { get; set; } = new List<RecentlyPlayedWithEntry>();


			[FSDisplayName("Banned Players")]
			[FSDescription("Players who are on this list will not be able to join any games <b>you host</b>.")]
			public List<BanListEntry> BanList { get; set; } = new List<BanListEntry>();

		}

		[Localized]
		public enum PlayerRelationShip
		{
			None,
			Self,
			Friend,
			Banned,
			Bot
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class SNet_SessionHub_SlaveWantsToJoin_Patch
		{
			public static bool Prefix(SNet_Player player)
			{
				if (SNet.IsMaster && IsPlayerBanned(player.Lookup))
				{
					FeatureLogger.Notice("Banned player \"" + player.GetName() + "\" tried to join, their join request has been ignored!");
					KickPlayer(player);
					return false;
				}
				return true;
			}
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class SNet_OnPlayerJoinedSessionHub_Patch
		{
			public static void Postfix(SNet_Player player)
			{
				AddRecentlyPlayedWith(player, joined: true);
			}
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class SNet_OnPlayerLeftSessionHub_Patch
		{
			public static void Prefix(SNet_Player player)
			{
				AddRecentlyPlayedWith(player, joined: false);
			}
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class CM_PlayerLobbyBar_UpdatePlayer_Patch
		{
			internal static Dictionary<int, BoxCollider2D> colliderMap = new Dictionary<int, BoxCollider2D>();

			private static MethodAccessor<GUIX_ElementSprite> A_Unregister;

			private static MethodAccessor<GUIX_ElementSprite> A_Start;

			private static IValueAccessor<GUIX_ElementSprite, GUIX_Layer> A_layer;

			public static void Init()
			{
				A_Start = MethodAccessor<GUIX_ElementSprite>.GetAccessor("Start", (Type[])null, false);
				A_Unregister = MethodAccessor<GUIX_ElementSprite>.GetAccessor("Unregister", (Type[])null, false);
				A_layer = AccessorBase.GetValueAccessor<GUIX_ElementSprite, GUIX_Layer>("layer", false);
			}

			public static void ColorizeNickNameGUIX(GameObject nickNameGuix, PlayerRelationShip rel = PlayerRelationShip.None)
			{
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)nickNameGuix == (Object)null)
				{
					return;
				}
				foreach (Transform item in SharedUtils.DirectChildren(nickNameGuix.transform))
				{
					GUIX_ElementSprite component = ((Component)item).GetComponent<GUIX_ElementSprite>();
					SpriteRenderer component2 = ((Component)item).GetComponent<SpriteRenderer>();
					if ((Object)(object)component2 != (Object)null)
					{
						if (!Settings.LobbyColors.ColorizeLobbyBullet)
						{
							component2.color = Color.white;
						}
						else if (rel != PlayerRelationShip.Self)
						{
							if (rel != PlayerRelationShip.Friend || !Settings.LobbyColors.RainbowPukeFriends)
							{
								goto IL_00cf;
							}
							component2.color = Random.ColorHSV();
						}
						else if (Settings.LobbyColors.RainbowPukeSelf)
						{
							component2.color = Random.ColorHSV();
						}
						else
						{
							if (!Settings.LobbyColors.UseNicknameColorForSelf || !FeatureManager.IsFeatureEnabled<Nickname>() || !Nickname.IsNicknameColorEnabled)
							{
								goto IL_00cf;
							}
							component2.color = Nickname.CurrentNicknameColor;
						}
					}
					goto IL_00db;
					IL_00cf:
					component2.color = GetRelationshipColor(rel);
					goto IL_00db;
					IL_00db:
					if (!((Object)(object)A_layer.Get(component) == (Object)null) && ((Component)component).gameObject.activeInHierarchy)
					{
						A_Unregister.Invoke(component);
						component.DynamicIndex = -1;
						A_layer.Set(component, (GUIX_Layer)null);
						A_Start.Invoke(component);
					}
				}
			}

			public static void Postfix(CM_PlayerLobbyBar __instance, SNet_Player player)
			{
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
				if (player == null)
				{
					return;
				}
				SNet_Slot characterSlot = player.CharacterSlot;
				if (characterSlot == null)
				{
					return;
				}
				_ = characterSlot.index;
				if (false)
				{
					return;
				}
				int playerLobbyBarIndex = SharedUtils.GetPlayerLobbyBarIndex(__instance);
				GameObject gameObject = ((Component)__instance.m_nickText).gameObject;
				CM_Item CM_Item = gameObject.GetComponent<CM_Item>();
				if ((Object)(object)CM_Item == (Object)null)
				{
					FeatureLogger.Debug($"Setting up player name button for slot index {playerLobbyBarIndex}");
					BoxCollider2D val = gameObject.AddComponent<BoxCollider2D>();
					val.size = new Vector2(447.2f, 52.8f);
					((Collider2D)val).offset = new Vector2(160f, 1.6f);
					if (colliderMap.ContainsKey(playerLobbyBarIndex))
					{
						colliderMap.Remove(playerLobbyBarIndex);
					}
					colliderMap.Add(playerLobbyBarIndex, val);
					CM_Item = gameObject.AddComponent<CM_Item>();
					CM_Item.ID = playerLobbyBarIndex + 1;
					SharedUtils.SetCMItemEvents(CM_Item, (Action<int>)delegate(int id)
					{
						if (!((RectTransformComp)PopupWindow).IsVisible || ((CM_PopupOverlay)PopupWindow).ID != id)
						{
							SetupAndPlaceWindow(id, ((Component)CM_Item).transform);
						}
						else
						{
							((RectTransformComp)PopupWindow).SetVisible(false);
						}
					}, (Action<int, bool>)null);
				}
				ColorizeNickNameGUIX(__instance.m_nickNameGuix, GetRelationship(player));
			}
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class PUI_Inventory_UpdateAllSlots_Patch
		{
			internal static Dictionary<int, BoxCollider2D> colliderMap = new Dictionary<int, BoxCollider2D>();

			public static void Postfix(PUI_Inventory __instance, SNet_Player player)
			{
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
				if (player == null)
				{
					return;
				}
				SNet_Slot characterSlot = player.CharacterSlot;
				if (characterSlot == null)
				{
					return;
				}
				_ = characterSlot.index;
				if (false)
				{
					return;
				}
				int index = player.CharacterSlot.index;
				GameObject headerRoot = __instance.m_headerRoot;
				if ((Object)(object)headerRoot.GetComponent<CM_Item>() == (Object)null)
				{
					FeatureLogger.Debug($"Setting up player name button (map) for index {player.CharacterSlot.index}");
					BoxCollider2D val = headerRoot.AddComponent<BoxCollider2D>();
					val.size = new Vector2(400f, 40f);
					((Collider2D)val).offset = new Vector2(-200f, 0f);
					if (colliderMap.ContainsKey(index))
					{
						colliderMap.Remove(index);
					}
					colliderMap.Add(index, val);
					CM_Item obj = headerRoot.AddComponent<CM_Item>();
					obj.ID = player.CharacterSlot.index + 1;
					SharedUtils.SetCMItemEvents(obj, (Action<int>)OnMapNameButtonPressed, (Action<int, bool>)null);
				}
			}
		}

		private static Dictionary<PlayerRelationShip, Color> _colorMap = new Dictionary<PlayerRelationShip, Color>();

		private static CM_ScrollWindow _popupWindow = null;

		public override string Name => "Player Lobby Management";

		public override FeatureGroup Group => FeatureGroups.Security;

		public override string Description => "Allows you to open a players steam profile by clicking on their name as well as kick and ban players as host.";

		public static ILocalizationService Localization { get; set; }

		public static IArchiveLogger FeatureLogger { get; set; }

		[FeatureConfig]
		public static LobbyManagementSettings Settings { get; set; }

		private static CM_ScrollWindow PopupWindow
		{
			get
			{
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
				//IL_0142: Unknown result type (might be due to invalid IL or missing references)
				//IL_0190: Unknown result type (might be due to invalid IL or missing references)
				//IL_0265: Unknown result type (might be due to invalid IL or missing references)
				//IL_0283: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_popupWindow == (Object)null)
				{
					FeatureLogger.Debug("Creating PopupWindow ...");
					_popupWindow = Object.Instantiate<CM_ScrollWindow>(PageSettingsData.PopupWindow, (Transform)(object)((CM_PageBase)CM_PageLoadout.Current).m_movingContentHolder);
					Object.DontDestroyOnLoad((Object)(object)_popupWindow);
					((Object)_popupWindow).name = "PlayerLobbyManagement_PopupWindow_PlayerManagement";
					((RectTransformComp)PopupWindow).Setup();
					OpenSteamItem = CreatePopupItem(Localization.Get(1u), OnNameButtonPressed);
					SharedUtils.ChangeColorCMItem(OpenSteamItem, ModSettings.GREEN, (Color?)null);
					SharedUtils.SetHoldDuration(SharedUtils.TryCastTo<CM_TimedButton>((Il2CppObjectBase)(object)OpenSteamItem), 0.5f);
					IsFriendItem = CreatePopupItem(Localization.Get(2u), delegate
					{
					});
					SharedUtils.ChangeColorCMItem(IsFriendItem, GetRelationshipColor(PlayerRelationShip.Friend), (Color?)null);
					SharedUtils.SetHoldDuration(SharedUtils.TryCastTo<CM_TimedButton>((Il2CppObjectBase)(object)IsFriendItem), 100f);
					((Behaviour)((Component)IsFriendItem).GetComponent<Collider2D>()).enabled = false;
					KickPlayerItem = CreatePopupItem(Localization.Get(3u), KickPlayerButtonPressed);
					SharedUtils.ChangeColorCMItem(KickPlayerItem, ModSettings.ORANGE, (Color?)null);
					SharedUtils.SetHoldDuration(SharedUtils.TryCastTo<CM_TimedButton>((Il2CppObjectBase)(object)KickPlayerItem), 2f);
					BanPlayerItem = CreatePopupItem(Localization.Get(4u), BanPlayerButtonPressed);
					SharedUtils.ChangeColorCMItem(BanPlayerItem, ModSettings.RED, (Color?)null);
					SharedUtils.SetHoldDuration(SharedUtils.TryCastTo<CM_TimedButton>((Il2CppObjectBase)(object)BanPlayerItem), 4f);
					CM_Item val = CreatePopupItem("Spacer, should not be visible", delegate
					{
					});
					List<iScrollWindowContent> val2 = SharedUtils.NewListForGame<iScrollWindowContent>();
					val2.Add(((Component)OpenSteamItem).GetComponentInChildren<iScrollWindowContent>());
					val2.Add(((Component)IsFriendItem).GetComponentInChildren<iScrollWindowContent>());
					val2.Add(((Component)val).GetComponentInChildren<iScrollWindowContent>());
					val2.Add(((Component)KickPlayerItem).GetComponentInChildren<iScrollWindowContent>());
					val2.Add(((Component)BanPlayerItem).GetComponentInChildren<iScrollWindowContent>());
					PopupWindow.SetContentItems(val2, 5f);
					((Component)val).gameObject.SetActive(false);
					((Component)val).transform.position = new Vector3(-5000f, 0f, 0f);
					((RectTransformComp)PopupWindow).SetSize(new Vector2(350f, (float)(58 * val2.Count)));
					((RectTransformComp)PopupWindow).SetVisible(false);
					PopupWindow.SetHeader("Player options");
				}
				return _popupWindow;
			}
		}

		internal static CM_Item OpenSteamItem { get; set; }

		internal static CM_Item IsFriendItem { get; set; }

		internal static CM_Item KickPlayerItem { get; set; }

		internal static CM_Item BanPlayerItem { get; set; }

		public override void OnEnable()
		{
			foreach (BoxCollider2D value in CM_PlayerLobbyBar_UpdatePlayer_Patch.colliderMap.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					((Behaviour)value).enabled = true;
				}
			}
			foreach (BoxCollider2D value2 in PUI_Inventory_UpdateAllSlots_Patch.colliderMap.Values)
			{
				if ((Object)(object)value2 != (Object)null)
				{
					((Behaviour)value2).enabled = true;
				}
			}
			SetupColorMap();
		}

		public override void OnDisable()
		{
			foreach (BoxCollider2D value in CM_PlayerLobbyBar_UpdatePlayer_Patch.colliderMap.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					((Behaviour)value).enabled = false;
				}
			}
			foreach (BoxCollider2D value2 in PUI_Inventory_UpdateAllSlots_Patch.colliderMap.Values)
			{
				if ((Object)(object)value2 != (Object)null)
				{
					((Behaviour)value2).enabled = false;
				}
			}
		}

		public override void OnFeatureSettingChanged(FeatureSetting setting)
		{
			SetupColorMap();
		}

		public static void SetupColorMap()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			_colorMap.Clear();
			PlayerRelationShip[] array = Enum.GetValues(typeof(PlayerRelationShip)) as PlayerRelationShip[];
			foreach (PlayerRelationShip playerRelationShip in array)
			{
				_colorMap.Add(playerRelationShip, GetRelationshipColor(playerRelationShip));
			}
		}

		public static PlayerRelationShip GetRelationship(PlayerAgent player)
		{
			return GetRelationship((player != null) ? player.Owner : null);
		}

		public static PlayerRelationShip GetRelationship(SNet_Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return PlayerRelationShip.None;
			}
			if (SharedUtils.SafeIsBot(player))
			{
				return PlayerRelationShip.Bot;
			}
			if (player.IsLocal)
			{
				return PlayerRelationShip.Self;
			}
			if (IsPlayerBanned(player.Lookup))
			{
				return PlayerRelationShip.Banned;
			}
			if (SharedUtils.IsFriend(player))
			{
				return PlayerRelationShip.Friend;
			}
			return PlayerRelationShip.None;
		}

		public static Color GetRelationshipColor(PlayerRelationShip rel)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			if (_colorMap.TryGetValue(rel, out var value))
			{
				return value;
			}
			return (Color)(rel switch
			{
				PlayerRelationShip.Self => SColorExtensions.ToUnityColor(Settings.LobbyColors.Self), 
				PlayerRelationShip.Bot => SColorExtensions.ToUnityColor(Settings.LobbyColors.Bots), 
				PlayerRelationShip.Friend => SColorExtensions.ToUnityColor(Settings.LobbyColors.Friends), 
				PlayerRelationShip.Banned => SColorExtensions.ToUnityColor(Settings.LobbyColors.Banned), 
				_ => SColorExtensions.ToUnityColor(Settings.LobbyColors.Default), 
			});
		}

		public static bool IsPlayerBanned(ulong lookup)
		{
			return Settings.BanList.Any((LobbyManagementSettings.BanListEntry bp) => bp.SteamID == lookup);
		}

		internal static void OnMapNameButtonPressed(int id)
		{
			if (Settings.NamesOnMapOpenSteamProfile)
			{
				SNet_Player player = default(SNet_Player);
				if (!SharedUtils.TryGetPlayerByCharacterIndex(id, ref player))
				{
					FeatureLogger.Debug($"No player found for character index {id - 1}.");
				}
				else
				{
					OpenSteamProfileFor(player);
				}
			}
		}

		internal static void OnNameButtonPressed(int id)
		{
			((RectTransformComp)PopupWindow).SetVisible(false);
			SNet_Player player = default(SNet_Player);
			if (!SharedUtils.TryGetPlayerByPlayerLobbyBarIndex(id - 1, ref player))
			{
				FeatureLogger.Debug($"No player found for index {id - 1}.");
			}
			else
			{
				OpenSteamProfileFor(player);
			}
		}

		public static void OpenSteamProfileFor(SNet_Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				FeatureLogger.Debug("Player was null!");
				return;
			}
			if (SharedUtils.SafeIsBot(player))
			{
				FeatureLogger.Notice("The Bot has no steam profile!");
				return;
			}
			FeatureLogger.Info($"Opening Steam profile for player \"{player.NickName}\" ({player.Lookup})");
			string text = $"https://steamcommunity.com/profiles/{player.Lookup}";
			if (Settings.PreferOpeningProfileLinksInSteamOverlay && SteamUtils.IsOverlayEnabled())
			{
				SteamFriends.ActivateGameOverlayToWebPage(text, (EActivateGameOverlayToWebPageMode)0);
			}
			else
			{
				Application.OpenURL(text);
			}
		}

		internal static void KickPlayerButtonPressed(int playerID)
		{
			((RectTransformComp)PopupWindow).SetVisible(false);
			SNet_Player val = default(SNet_Player);
			if (SNet.IsMaster && SharedUtils.TryGetPlayerByPlayerLobbyBarIndex(playerID - 1, ref val))
			{
				if (SharedUtils.SafeIsBot(val))
				{
					FeatureLogger.Notice("Use the built in button below to remove bots!");
					return;
				}
				FeatureLogger.Notice($"Kicking player \"{val.GetName()}\" Nick:\"{val.NickName}\" ...");
				KickPlayer(val);
			}
		}

		internal static void BanPlayerButtonPressed(int playerID)
		{
			SNet_Player val = default(SNet_Player);
			if (!SharedUtils.TryGetPlayerByPlayerLobbyBarIndex(playerID - 1, ref val))
			{
				return;
			}
			if (val.IsLocal)
			{
				BanPlayerItem.SetText(" You can't ban yourself, silly!");
				return;
			}
			((RectTransformComp)PopupWindow).SetVisible(false);
			if (SharedUtils.SafeIsBot(val))
			{
				FeatureLogger.Notice("You can't ban a bot!");
			}
			else if (!IsPlayerBanned(val.Lookup))
			{
				BanPlayer(val);
			}
			else
			{
				UnbanPlayer(val);
			}
		}

		public static bool BanPlayer(SNet_Player player, bool kickPlayer = true)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			if (!IsPlayerBanned(player.Lookup))
			{
				Settings.BanList.Add(new LobbyManagementSettings.BanListEntry
				{
					Name = player.GetName(),
					SteamID = player.Lookup,
					Timestamp = DateTime.UtcNow.Ticks
				});
				FeatureLogger.Fail($"Player has been added to list of banned players: Name:\"{player.GetName()}\" SteamID:\"{player.Lookup}\"");
				Feature.MarkSettingsAsDirty<LobbyManagementSettings>(Settings);
				if (kickPlayer)
				{
					KickPlayer(player);
				}
				return true;
			}
			return false;
		}

		public static bool UnbanPlayer(SNet_Player player)
		{
			return UnbanPlayer((player != null) ? player.Lookup : ulong.MaxValue);
		}

		public static bool UnbanPlayer(ulong playerID)
		{
			if (playerID == ulong.MaxValue)
			{
				return false;
			}
			LobbyManagementSettings.BanListEntry banListEntry = Settings.BanList.FirstOrDefault((LobbyManagementSettings.BanListEntry entry) => entry.SteamID == playerID);
			if (banListEntry != null)
			{
				Settings.BanList.Remove(banListEntry);
				FeatureLogger.Success($"Player has been removed from the list of banned players: Name:\"{banListEntry.Name}\" SteamID:\"{banListEntry.SteamID}\"");
				Feature.MarkSettingsAsDirty<LobbyManagementSettings>(Settings);
				return true;
			}
			return false;
		}

		public static void KickPlayer(SNet_Player player)
		{
			if (SNet.IsMaster)
			{
				SNet.Sync.KickPlayer(player, (SNet_PlayerEventReason)2);
			}
		}

		private static CM_Item CreatePopupItem(string text, Action<int> onClick, int id = 0)
		{
			CM_Item val = SharedUtils.TryCastTo<CM_Item>((Il2CppObjectBase)(object)GOUtil.SpawnChildAndGetComp<iScrollWindowContent>(UIHelper.PopupItemPrefab, ((Component)_popupWindow).transform));
			val.SetupCMItem();
			if (id != 0)
			{
				val.ID = id;
			}
			val.SetText(text);
			SharedUtils.SetCMItemEvents(val, onClick, (Action<int, bool>)null);
			((RectTransformComp)val).ForcePopupLayer(true, (GameObject)null);
			return val;
		}

		public static void SetupAndPlaceWindow(int playerID, Transform pos)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			SNet_Player val = default(SNet_Player);
			if (!SharedUtils.TryGetPlayerByPlayerLobbyBarIndex(playerID - 1, ref val))
			{
				return;
			}
			string name = val.GetName();
			bool flag = SharedUtils.SafeIsBot(val);
			((Component)KickPlayerItem).gameObject.SetActive(!flag);
			((Component)BanPlayerItem).gameObject.SetActive(!flag);
			((Component)OpenSteamItem).gameObject.SetActive(!flag);
			if (flag)
			{
				((Component)IsFriendItem).gameObject.SetActive(true);
				IsFriendItem.SetText(Localization.Get(6u));
				SharedUtils.ChangeColorCMItem(IsFriendItem, GetRelationshipColor(PlayerRelationShip.Bot), (Color?)null);
				ShowWindow(name, pos, playerID);
				return;
			}
			((CM_PopupOverlay)PopupWindow).SetupFromButton(new iCellMenuPopupController(((Il2CppObjectBase)CM_PageLoadout.Current).Pointer), (CM_PageBase)(object)CM_PageLoadout.Current);
			SNet_Friend val2 = default(SNet_Friend);
			bool flag2 = SNet.Friends.TryGetFriend(val.Lookup, ref val2);
			bool flag3 = IsPlayerBanned(val.Lookup);
			((Component)IsFriendItem).gameObject.SetActive(flag2 || flag3);
			if (flag3)
			{
				IsFriendItem.SetText(Localization.Get(5u));
				SharedUtils.ChangeColorCMItem(IsFriendItem, GetRelationshipColor(PlayerRelationShip.Banned), (Color?)null);
			}
			else if (flag2)
			{
				IsFriendItem.SetText(Localization.Get(2u));
				SharedUtils.ChangeColorCMItem(IsFriendItem, GetRelationshipColor(PlayerRelationShip.Friend), (Color?)null);
			}
			KickPlayerItem.SetText(Localization.Format(7u, new object[1] { name }));
			if (val.IsMaster || !SNet.IsMaster)
			{
				((Behaviour)((Component)KickPlayerItem).GetComponent<Collider2D>()).enabled = false;
				SharedUtils.ChangeColorCMItem(KickPlayerItem, ModSettings.DISABLED, (Color?)null);
				BanPlayerItem.SetText(Localization.Format(8u, new object[1] { name }));
			}
			else
			{
				((Behaviour)((Component)KickPlayerItem).GetComponent<Collider2D>()).enabled = true;
				SharedUtils.ChangeColorCMItem(KickPlayerItem, ModSettings.ORANGE, (Color?)null);
				BanPlayerItem.SetText(Localization.Format(9u, new object[1] { name }));
			}
			if (val.IsLocal)
			{
				SharedUtils.ChangeColorCMItem(BanPlayerItem, ModSettings.DISABLED, (Color?)null);
			}
			else if (flag3)
			{
				BanPlayerItem.SetText(Localization.Format(10u, new object[1] { name }));
				SharedUtils.ChangeColorCMItem(BanPlayerItem, ModSettings.GREEN, (Color?)null);
			}
			else
			{
				SharedUtils.ChangeColorCMItem(BanPlayerItem, ModSettings.RED, (Color?)null);
			}
			ShowWindow(name, pos, playerID);
		}

		private static void ShowWindow(string header, Transform pos, int playerID)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			PopupWindow.SetHeader(header);
			((CM_PopupOverlay)PopupWindow).ID = playerID;
			((Component)PopupWindow).transform.position = pos.position + new Vector3(200f, 0f, 0f);
			OpenSteamItem.ID = playerID;
			KickPlayerItem.ID = playerID;
			BanPlayerItem.ID = playerID;
			((RectTransformComp)PopupWindow).SetVisible(true);
		}

		private static void AddRecentlyPlayedWith(SNet_Player player, bool joined)
		{
			LobbyManagementSettings.RecentlyPlayedWithEntry recentlyPlayedWithEntry = Settings.RecentlyPlayedWith.FirstOrDefault((LobbyManagementSettings.RecentlyPlayedWithEntry entry) => entry.SteamID == player.Lookup);
			if (recentlyPlayedWithEntry != null)
			{
				if (joined)
				{
					FeatureLogger.Notice($"{player.NickName} joined Session, last time played with them {DateTime.UtcNow - new DateTime(recentlyPlayedWithEntry.TimestampLast):d' day(s) and 'hh':'mm':'ss} ago.");
				}
				else
				{
					FeatureLogger.Debug(player.NickName + " left Session, saving Timestamp.");
				}
				recentlyPlayedWithEntry.TimestampLast = DateTime.UtcNow.Ticks;
				Feature.MarkSettingsAsDirty<LobbyManagementSettings>(Settings);
			}
			else
			{
				long ticks = DateTime.UtcNow.Ticks;
				Settings.RecentlyPlayedWith.Add(new LobbyManagementSettings.RecentlyPlayedWithEntry
				{
					Name = player.NickName,
					SteamID = player.Lookup,
					TimestampFirst = ticks,
					TimestampLast = ticks
				});
				Feature.MarkSettingsAsDirty<LobbyManagementSettings>(Settings);
			}
		}
	}
}
namespace TheArchive.Features.QoL
{
	public class IntroSkip : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class CM_PageIntro_Update_Patch
		{
			private static bool _injectPressed;

			private static MethodAccessor<CM_PageIntro> _onSkip;

			public static void Init()
			{
				_onSkip = MethodAccessor<CM_PageIntro>.GetAccessor("OnSkip", (Type[])null, false);
			}

			[IsPostfix]
			[RundownConstraint(/*Could not decode attribute arguments.*/)]
			public static void PostfixR4OrLater(CM_PageIntro __instance)
			{
				CheckAndSkipIfReady(__instance, __instance.m_startupLoaded, __instance.m_enemiesLoaded, __instance.m_sharedLoaded);
			}

			public static void CheckAndSkipIfReady(CM_PageIntro __instance, bool ___m_startupLoaded, bool ___m_enemiesLoaded, bool ___m_sharedLoaded)
			{
				if (___m_startupLoaded && ___m_enemiesLoaded && ___m_sharedLoaded && ItemSpawnManager.ReadyToSpawnItems && IsProgressionFileReady() && !_injectPressed)
				{
					FeatureLogger.Notice("Automatically pressing the Inject button ...");
					_onSkip.Invoke(__instance);
					__instance.EXT_PressInject(-1);
					_injectPressed = true;
				}
			}
		}

		public override string Name => "Skip Intro";

		public override FeatureGroup Group => FeatureGroups.QualityOfLife;

		public override string Description => "Automatically presses inject at the start of the game";

		public static IArchiveLogger FeatureLogger { get; set; }

		public static bool IsProgressionFileReady()
		{
			return RundownManager.RundownProgressionReady;
		}
	}
	public class L4DStylePacks : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class ResourcePackFirstPerson_UpdateInteraction_Patch
		{
			private static MethodAccessor<ResourcePackFirstPerson> A_UpdateInteractionActionName;

			private static IValueAccessor<Interact_Timed, PlayerAgent> A_m_interactionSourceAgent;

			private static IValueAccessor<Interact_Timed, float> A_m_interactionTimer;

			public static void Init()
			{
				A_UpdateInteractionActionName = MethodAccessor<ResourcePackFirstPerson>.GetAccessor("UpdateInteractionActionName", (Type[])null, false);
				if (!Is.R6OrLater)
				{
					A_m_interactionSourceAgent = AccessorBase.GetValueAccessor<Interact_Timed, PlayerAgent>("m_interactionSourceAgent", false);
					A_m_interactionTimer = AccessorBase.GetValueAccessor<Interact_Timed, float>("m_interactionTimer", false);
				}
			}

			public static bool Prefix(ResourcePackFirstPerson __instance)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0127: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_019f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0172: Unknown result type (might be due to invalid IL or missing references)
				//IL_026b: Unknown result type (might be due to invalid IL or missing references)
				iResourcePackReceiver val = __instance.m_actionReceiver;
				iResourcePackReceiver lastActionReceiver = __instance.m_lastActionReceiver;
				eResourceContainerSpawnType packType = __instance.m_packType;
				Interact_ManualTimedWithCallback interactApplyResource = __instance.m_interactApplyResource;
				bool flag = false;
				bool flag2 = false;
				InputAction input = (InputAction)0;
				if (InputMapper.GetButtonDown.Invoke((InputAction)8, ((Item)__instance).Owner.InputFilter))
				{
					flag = true;
					if (!((Interact_Timed)interactApplyResource).TimerIsActive)
					{
						val = (__instance.m_actionReceiver = SharedUtils.CastTo<iResourcePackReceiver>((Il2CppObjectBase)(object)((Item)__instance).Owner));
					}
					input = (InputAction)8;
				}
				if (InputMapper.GetButton.Invoke((InputAction)7, ((Item)__instance).Owner.InputFilter))
				{
					flag2 = true;
					flag = true;
					RaycastHit val3 = default(RaycastHit);
					if (!((Interact_Timed)interactApplyResource).TimerIsActive && Physics.Raycast(((Item)__instance).Owner.FPSCamera.Position, ((Item)__instance).Owner.FPSCamera.Forward, ref val3, 2.4f, LayerManager.MASK_GIVE_RESOURCE_PACK))
					{
						iResourcePackReceiver componentInParent = ((Component)((RaycastHit)(ref val3)).collider).GetComponentInParent<iResourcePackReceiver>();
						if (componentInParent != null)
						{
							val = (__instance.m_actionReceiver = componentInParent);
						}
					}
					input = ((!val.IsLocallyOwned) ? ((InputAction)7) : ((InputAction)8));
				}
				if (val == null || (!((Interact_Timed)interactApplyResource).TimerIsActive && !flag))
				{
					val = (__instance.m_actionReceiver = SharedUtils.CastTo<iResourcePackReceiver>((Il2CppObjectBase)(object)((Item)__instance).Owner));
					if (Is.R6OrLater)
					{
						OnInteractorStateChangedR6Plus(interactApplyResource, ((Item)__instance).Owner, state: false);
					}
					((Interact_Base)interactApplyResource).PlayerSetSelected(false, ((Item)__instance).Owner);
				}
				bool flag3 = NeedsResource(val, packType);
				if (!((Interact_Timed)interactApplyResource).TimerIsActive && val != lastActionReceiver)
				{
					if (val.IsLocallyOwned)
					{
						A_UpdateInteractionActionName.Invoke(__instance, new object[2]
						{
							Localization.Get(7u),
							true
						});
						interactApplyResource.m_input = input;
					}
					else
					{
						A_UpdateInteractionActionName.Invoke(__instance, new object[2] { val.InteractionName, false });
						interactApplyResource.m_input = input;
						if (flag3)
						{
							if (Is.R6OrLater)
							{
								OnInteractorStateChangedR6Plus(interactApplyResource, ((Item)__instance).Owner, state: true);
							}
							else
							{
								ActivateTimerR5AndBelow(interactApplyResource, ((Item)__instance).Owner);
							}
						}
					}
					__instance.m_lastActionReceiver = val;
				}
				bool timerIsActive = ((Interact_Timed)interactApplyResource).TimerIsActive;
				interactApplyResource.ManualUpdateWithCondition(flag3, ((Item)__instance).Owner, flag3 && !val.IsLocallyOwned);
				bool timerIsActive2 = ((Interact_Timed)interactApplyResource).TimerIsActive;
				if (!timerIsActive && timerIsActive2 && Is.R6OrLater)
				{
					SendGenericInteractR6Plus(__instance, val);
				}
				if (timerIsActive && !timerIsActive2)
				{
					PlayerAgent owner = ((Item)__instance).Owner;
					__instance.m_actionReceiver = ((owner != null) ? SharedUtils.CastTo<iResourcePackReceiver>((Il2CppObjectBase)(object)owner) : null);
				}
				if (!flag3 && flag && __instance.m_lastButtonDown != flag && (!flag2 || !val.IsLocallyOwned))
				{
					SharedUtils.SafePost(((ItemEquippable)__instance).Sound, EVENTS.BUTTONGENERICBLIPDENIED, true);
					ShowDoesNotNeedResourcePrompt(val, packType);
				}
				__instance.m_lastButtonDown = flag;
				return false;
			}

			private static void ActivateTimerR5AndBelow(Interact_ManualTimedWithCallback timer, PlayerAgent agent)
			{
				A_m_interactionSourceAgent.Set((Interact_Timed)(object)timer, agent);
				((Interact_Timed)timer).SetTimerActive(true);
				A_m_interactionTimer.Set((Interact_Timed)(object)timer, Clock.Delta);
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			private static void SendGenericInteractR6Plus(ResourcePackFirstPerson __instance, iResourcePackReceiver packReceiver)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				TypeEnum val = (TypeEnum)(packReceiver.IsLocallyOwned ? 6 : 5);
				((Item)__instance).Owner.Sync.SendGenericInteract(val, false);
			}

			[MethodImpl(MethodImplOptions.NoInlining)]
			private static void OnInteractorStateChangedR6Plus(Interact_ManualTimedWithCallback timer, PlayerAgent sourceAgent, bool state)
			{
				((Interact_Timed)timer).OnInteractorStateChanged(sourceAgent, state);
			}
		}

		private static MethodAccessor<InteractionGuiLayer> A_SetTimedMessage;

		public override string Name => "L4D Style Resource Packs";

		public override FeatureGroup Group => FeatureGroups.QualityOfLife;

		public override string Description => "Use left and right mouse buttons to apply resource packs instead of E.\n\nLeft mouse = yourself\nRight mouse = other players\n\n<color=orange>[R4+]</color> You're able to hold down M2 and it will start applying to a receiver under your croshair if in range automatically\n\n<#f00><u>/!\\</u> Make sure to <color=orange><u>disable</u></color> the vanilla game setting <color=orange>Gameplay > Separate Use Keybinds</color> for this Feature to work!</color>";

		public static ILocalizationService Localization { get; set; }

		public static IArchiveLogger FeatureLogger { get; set; }

		public override void Init()
		{
			if (!Is.R2OrLater)
			{
				A_SetTimedMessage = MethodAccessor<InteractionGuiLayer>.GetAccessor("SetTimedMessage", (Type[])null, false);
			}
		}

		public static bool NeedsResource(iResourcePackReceiver receiver, eResourceContainerSpawnType packType)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected I4, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			if (receiver == null)
			{
				return false;
			}
			switch ((int)packType)
			{
			default:
				if ((int)packType == 9)
				{
					if (Is.R2OrLater)
					{
						return NeedsDisinfect(receiver);
					}
					return false;
				}
				return false;
			case 0:
				return receiver.NeedHealth();
			case 1:
				return receiver.NeedWeaponAmmo();
			case 2:
				return receiver.NeedToolAmmo();
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static bool NeedsDisinfect(iResourcePackReceiver receiver)
		{
			return receiver.NeedDisinfection();
		}

		public static void ShowDoesNotNeedResourcePrompt(iResourcePackReceiver receiver, eResourceContainerSpawnType packType)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected I4, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			string text = (receiver.IsLocallyOwned ? Localization.Get(1u) : Localization.Format(2u, new object[1] { receiver.InteractionName }));
			switch ((int)packType)
			{
			default:
				if ((int)packType == 9)
				{
					text += Localization.Get(6u);
				}
				break;
			case 1:
				text += Localization.Get(3u);
				break;
			case 2:
				text += Localization.Get(4u);
				break;
			case 0:
				text += Localization.Get(5u);
				break;
			}
			SetTimedInteractionPrompt(text, 1.4f);
		}

		private static void SetTimedInteractionPrompt(string text, float time)
		{
			if (Is.R2OrLater)
			{
				TimedInteractionPromptR2Plus(text, time);
				return;
			}
			A_SetTimedMessage.Invoke(GuiManager.InteractionLayer, new object[3]
			{
				text,
				time,
				(object)(ePUIMessageStyle)1
			});
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private static void TimedInteractionPromptR2Plus(string text, float time)
		{
			GuiManager.InteractionLayer.SetTimedInteractionPrompt(text, time, (ePUIMessageStyle)0);
		}
	}
	public class LastUsedGearSwitcher : Feature
	{
		public class LastUsedGearSwitcherSettings
		{
			[FSDisplayName("Quick Swap Key")]
			[FSDescription("Press this key to switch to the previously wielded gear.")]
			public KeyCode QuickSwitchKey { get; set; } = (KeyCode)120;


			[FSHide]
			[FSDisplayName("Prints Debug Info")]
			[FSDescription("Prints debug info to the console")]
			public bool DebugLog { get; set; }
		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class PlayerSync_WantsToWieldSlot_Patch
		{
			public static void Prefix(PlayerSync __instance, InventorySlot slot)
			{
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
				IReplicator replicator = __instance.Replicator;
				bool? obj;
				if (replicator == null)
				{
					obj = null;
				}
				else
				{
					SNet_Player owningPlayer = replicator.OwningPlayer;
					obj = ((owningPlayer != null) ? new bool?(owningPlayer.IsLocal) : null);
				}
				bool? flag = obj;
				if (flag.GetValueOrDefault())
				{
					InventorySlot wieldedSlot = __instance.GetWieldedSlot();
					if (Settings.DebugLog)
					{
						FeatureLogger.Debug($"PlayerSync.WantsToWieldSlot: currentSlot:{wieldedSlot} -> slot:{slot} | _previousInventorySlot:{_previousInventorySlot}");
					}
					if (wieldedSlot != slot)
					{
						_previousInventorySlot = wieldedSlot;
					}
				}
			}
		}

		private static readonly eFocusState _eFocusState_FPS = Utils.GetEnumFromName<eFocusState>("FPS");

		private static eFocusState _eFocusState_FPS_CommunicationDialog;

		private static InventorySlot _previousInventorySlot = (InventorySlot)10;

		public override string Name => "Last Used Gear Switcher";

		public override FeatureGroup Group => FeatureGroups.QualityOfLife;

		public override string Description => "Allows you to swap between the last two used weapons via a keypress";

		public static IArchiveLogger FeatureLogger { get; set; }

		[FeatureConfig]
		public static LastUsedGearSwitcherSettings Settings { get; set; }

		public override void Init()
		{
			if (Is.R6OrLater)
			{
				Utils.TryGetEnumFromName<eFocusState>("FPS_CommunicationDialog", ref _eFocusState_FPS_CommunicationDialog);
			}
		}

		public override void Update()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if ((FocusStateManager.CurrentState == _eFocusState_FPS || (Is.R6OrLater && FocusStateManager.CurrentState == _eFocusState_FPS_CommunicationDialog)) && Input.GetKeyDown(Settings.QuickSwitchKey))
			{
				SwitchToPreviousSlot();
			}
		}

		public static void SwitchToPreviousSlot()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
			InventorySlot previousInventorySlot = _previousInventorySlot;
			InventorySlot wieldedSlot = localPlayerAgent.Inventory.WieldedSlot;
			if (Settings.DebugLog)
			{
				FeatureLogger.Debug($"Switching to previous slot: {wieldedSlot} -> {previousInventorySlot}");
			}
			localPlayerAgent.Sync.WantsToWieldSlot(previousInventorySlot, false);
		}
	}
	public class LoadoutRandomizer : Feature
	{
		public class LoadoutRandomizerSettings
		{
			[Localized]
			public enum InventorySlots
			{
				Primary,
				Special,
				Tool,
				Melee
			}

			[Localized]
			public enum RandomizerMode
			{
				True,
				NoDuplicate
			}

			[FSDisplayName("Do not randomize")]
			public List<InventorySlots> ExcludedSlots { get; set; } = new List<InventorySlots>();


			[FSDisplayName("Mode")]
			public RandomizerMode Mode { get; set; } = RandomizerMode.NoDuplicate;

		}

		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		public static class CM_PageLoadout_SetupPatch
		{
			public static void Postfix(CM_PageLoadout __instance)
			{
				SetupViaInstance(__instance);
			}
		}

		private static CM_TimedButton _loadoutRandomizerButton;

		private static bool _hasBeenSetup = false;

		private static eGameStateName _eGameStateName_Lobby;

		private static readonly Dictionary<InventorySlot, LoadoutRandomizerSettings.InventorySlots> _invSlotMap = new Dictionary<InventorySlot, LoadoutRandomizerSettings.InventorySlots>
		{
			{
				Utils.GetEnumFromName<InventorySlot>("GearMelee"),
				LoadoutRandomizerSettings.InventorySlots.Melee
			},
			{
				Utils.GetEnumFromName<InventorySlot>("GearStandard"),
				LoadoutRandomizerSettings.InventorySlots.Primary
			},
			{
				Utils.GetEnumFromName<InventorySlot>("GearSpecial"),
				LoadoutRandomizerSettings.InventorySlots.Special
			},
			{
				Utils.GetEnumFromName<InventorySlot>("GearClass"),
				LoadoutRandomizerSettings.InventorySlots.Tool
			}
		};

		public override string Name => "Loadout Randomizer";

		public override FeatureGroup Group => FeatureGroups.QualityOfLife;

		public override string Description => "Adds a Loadout Randomizer button onto the loadout screen.\nSelect which gear to randomize via the settings below.";

		public static IArchiveLogger FeatureLogger { get; set; }

		[FeatureConfig]
		public static LoadoutRandomizerSettings Config { get; set; }

		public static bool IsEnabled { get; set; }

		public override void Init()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			_eGameStateName_Lobby = Utils.GetEnumFromName<eGameStateName>("Lobby");
		}

		public override void OnEnable()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between I4 and Unknown
			if (!_hasBeenSetup)
			{
				SetupViaInstance(CM_PageLoadout.Current);
			}
			if ((byte)Feature.CurrentGameState == (int)_eGameStateName_Lobby)
			{
				SetButtonActive();
			}
		}

		public override void OnDisable()
		{
			CM_TimedButton loadoutRandomizerButton = _loadoutRandomizerButton;
			if (loadoutRandomizerButton != null)
			{
				GameObject gameObject = ((Component)loadoutRandomizerButton).gameObject;
				if (gameObject != null)
				{
					gameObject.SetActive(false);
				}
			}
		}

		public void OnGameStateChanged(eGameStateName state)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (state == _eGameStateName_Lobby)
			{
				SetButtonActive();
			}
			else
			{
				SetButtonInactive();
			}
		}

		public static void SetupViaInstance(CM_PageLoadout pageLoadout)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)pageLoadout == (Object)null))
			{
				CM_TimedButton readyButton = pageLoadout.m_readyButton;
				CM_Item changeLoadoutButton = null;
				GameBuildInfo buildInfo = Feature.BuildInfo;
				if (RundownFlagsExtensions.IsIncludedIn(((GameBuildInfo)(ref buildInfo)).Rundown, RundownFlagsExtensions.ToLatest((RundownFlags)32)))
				{
					GetChangeLoadoutButtonR6Plus(pageLoadout, out changeLoadoutButton);
				}
				SetupButton(readyButton, changeLoadoutButton);
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		public static void GetChangeLoadoutButtonR6Plus(CM_PageLoadout pageLoadout, out CM_Item changeLoadoutButton)
		{
			changeLoadoutButton = pageLoadout.m_changeLoadoutButton;
		}

		private static void SetupButton(CM_TimedButton readyUpButton, CM_Item changeLoadoutButton = null)
		{
			//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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (_hasBeenSetup)
			{
				return;
			}
			GameBuildInfo buildInfo = Feature.BuildInfo;
			if (RundownFlagsExtensions.IsIncludedIn(((GameBuildInfo)(ref buildInfo)).Rundown, RundownFlagsExtensions.ToLatest((RundownFlags)32)))
			{
				SharedUtils.AddCMItemEvents((CM_Item)(object)readyUpButton, (Action<int>)SetButtonInactive, (Action<int, bool>)null);
				if (changeLoadoutButton != null)
				{
					SharedUtils.AddCMItemEvents(changeLoadoutButton, (Action<int>)SetButtonActive, (Action<int, bool>)null);
				}
			}
			CreateButton(readyUpButton);
			_hasBeenSetup = true;
		}

		private static CM_TimedButton CreateButton(CM_TimedButton prefab)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			_loadoutRandomizerButton = Object.Instantiate<GameObject>(((Component)prefab).gameObject, ((Component)prefab).transform.parent).GetComponent<CM_TimedButton>();
			SharedUtils.SetCMItemEvents((CM_Item)(object)_loadoutRandomizerButton, (Action<int>)OnRandomizeLoadoutButtonPressed, (Action<int, bool>)OnButtonHoverChanged);
			((Component)_loadoutRandomizerButton).gameObject.transform.Translate(new Vector3(-500f, 0f, 0f));
			BoxCollider2D component = ((Component)_loadoutRandomizerButton).GetComponent<BoxCollider2D>();
			if ((Object)(object)component != (Object)null)
			{
				((Collider2D)component).offset = new Vector2(0f, -40f);
			}
			((CM_Item)_loadoutRandomizerButton).SetText("Randomize Loadout");
			SharedUtils.ChangeColorTimedExpeditionButton(_loadoutRandomizerButton, new Color(1f, 1f, 1f, 0.5f));
			SetButtonActive();
			return _loadoutRandomizerButton;
		}

		private static void SetButtonActive(int _ = 0)
		{
			CM_TimedButton loadoutRandomizerButton = _loadoutRandomizerButton;
			if (loadoutRandomizerButton != null)
			{
				GameObject gameObject = ((Component)loadoutRandomizerButton).gameObject;
				if (gameObject != null)
				{
					gameObject.SetActive(IsEnabled);
				}
			}
		}

		public static void SetButtonInactive(int _ = 0)
		{
			CM_TimedButton loadoutRandomizerButton = _loadoutRandomizerButton;
			if (loadoutRandomizerButton != null)
			{
				GameObject gameObject = ((Component)loadoutRandomizerButton).gameObject;
				if (gameObject != null)
				{
					gameObject.SetActive(false);
				}
			}
		}

		public static void OnRandomizeLoadoutButtonPressed(int _)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			FeatureLogger.Notice("Randomizer Button has been pressed!");
			CM_PlayerLobbyBar val = null;
			val = ((IEnumerable<CM_PlayerLobbyBar>)((IEnumerable<CM_PlayerLobbyBar>)CM_PageLoadout.Current.m_playerLobbyBars).ToArray()).FirstOrDefault((Func<CM_PlayerLobbyBar, bool>)delegate(CM_PlayerLobbyBar plb)
			{
				SNet_Player player = plb.m_player;
				int? num = ((player != null) ? new int?(player.CharacterIndex) : null);
				PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
				return num == ((localPlayerAgent != null) ? new int?(localPlayerAgent.CharacterID) : null);
			});
			if ((Object)(object)val == (Object)null)
			{
				FeatureLogger.Error("Couldn't find the local players CM_PlayerLobbyBar, aborting randomization of loadout!");
				return;
			}
			Enumerator<InventorySlot, CM_InventorySlotItem> enumerator = val.m_inventorySlotItems.GetEnumerator();
			BackpackItem val2 = default(BackpackItem);
			while (enumerator.MoveNext())
			{
				KeyValuePair<InventorySlot, CM_InventorySlotItem> current = enumerator.Current;
				InventorySlot key = current.Key;
				if (!_invSlotMap.TryGetValue(key, out var value) || !Config.ExcludedSlots.Contains(value))
				{
					GearIDRange[] array = Il2CppArrayBase<GearIDRange>.op_Implicit((Il2CppArrayBase<GearIDRange>)(object)GearManager.GetAllGearForSlot(key));
					PlayerBackpackManager.LocalBackpack.TryGetBackpackItem(key, ref val2);
					GearIDRange currentGearIdForSlot = val2.GearIDRange;
					LoadoutRandomizerSettings.RandomizerMode mode = Config.Mode;
					GearIDRange val3 = ((mode == LoadoutRandomizerSettings.RandomizerMode.True || mode != LoadoutRandomizerSettings.RandomizerMode.NoDuplicate) ? Utils.PickRandom<GearIDRange>(array) : Utils.PickRandomExcept<GearIDRange>(array, (Func<GearIDRange, bool>)((GearIDRange random) => !currentGearIdForSlot.GetChecksum().Equals(random.GetChecksum()))));
					if (val3 == null)
					{
						FeatureLogger.Error($"Tried to randomize Gear for slot {key} but received null!");
						continue;
					}
					FeatureLogger.Notice($"Picked random gear \"{val3.PublicGearName}\" for slot {key}!");
					PlayerBackpackManager.ResetLocalAmmoStorage(false);
					PlayerBackpackManager.EquipLocalGear(val3);
					GearManager.RegisterGearInSlotAsEquipped(val3.PlayfabItemInstanceId, key);
				}
			}
		}

		public static void OnButtonHoverChanged(int i, bool b)
		{
		}
	}
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	internal class NoDroppedMagazineSounds : Feature
	{
		public override string Name => "No Magazine Drop Sound";

		public override FeatureGroup Group => FeatureGroups.QualityOfLife;

		public override string Description => "Removes the <i>globally audible</i> sound whenever a magazine drops on the floor after a reload.";

		public override bool RequiresRestart => true;

		public override void OnGameDataInitialized()
		{
			if (!((Feature)this).Enabled)
			{
				return;
			}
			foreach (GearMagPartDataBlock allBlock in GameDataBlockBase<GearMagPartDataBlock>.GetAllBlocks())
			{
				allBlock.DropSoundType = (MagazineDropSoundType)0;
			}
		}
	}
	[EnableFeatureByDefault]
	public class NoNavMarkerHideInChat : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class GuiManager_OnFocusStateChanged_Patch
		{
			private static eFocusState _eFocusState_FPS_TypingInChat;

			public static void Init()
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				_eFocusState_FPS_TypingInChat = Utils.GetEnumFromName<eFocusState>("FPS_TypingInChat");
			}

			public static void Postfix(eFocusState state)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				if (state == _eFocusState_FPS_TypingInChat)
				{
					((GuiLayer)GuiManager.NavMarkerLayer).SetVisible(true);
				}
			}
		}

		public override string Name => "See NavMarkers in Chat";

		public override FeatureGroup Group => FeatureGroups.QualityOfLife;

		public override string Description => "Prevent enemy pings from hiding whenever the chat is open.";
	}
	[RundownConstraint(/*Could not decode attribute arguments.*/)]
	public class NoStoryDialog : Feature
	{
		[ArchivePatch(/*Could not decode attribute arguments.*/)]
		internal static class WardenObjectiveManager_CheckAndExecuteEventsOnTrigger_Patch
		{
			[IsPrefix]
			[RundownConstraint(/*Could not decode attribute arguments.*/)]
			public static void PrefixR7(WardenObjectiveEventData eventToTrigger)
			{
				if (eventToTrigger.SoundSubtitle.HasValue)
				{
					FeatureLogger.Notice($"SoundEvent about to execute was: {eventToTrigger.SoundID} ({SoundEventCache.ReverseResolve(eventToTrigger.SoundID, false)})");
					eventToTrigger.SoundID = 0u;
				}
			}

			[IsPrefix]
			[RundownConstraint(/*Could not decode attribute arguments.*/)]
			public static void PrefixR6(WardenObjectiveEventData eventToTrigger)
			{
				if (eventToTrigger.SoundID != 0)
				{
					FeatureLogger.Notice($"SoundEvent about to execute was: {eventToTrigger.SoundID} ({SoundEventCache.ReverseResolve(eventToTrigger.SoundID, false)})");
					eventToTrigger.SoundID = 0u;
				}
			}
		}

		public override string Name => "Remove Story Dialog";

		public override FeatureGroup Group => FeatureGroups.QualityOfLife;

		public override string Description => "Removes all level-based voice events that come with subtitles.\naka Schaeffer-be-gone";

		public static IArchiveLogger FeatureLogger { get; set; }
	}
	public class ReloadSoundCue : Feature
	{
		public class ReloadSoundCueSettings
		{
			[FSDisplayName("Test Sound Event")]
			[FSDescription("Plays the sound event below,\nit's a little janky and might not work depending on the sound, sorry!")]
			public FButton TestSoundButton { get; set; } = new FButton("Play Sound", (string)null, (Action)null, false);


			[FSDisplayName("Sound Event")]
			[FSDescription("The sound event to play whenever the reload has happened.")]
			public string SoundEvent { get; set; } = "HACKING_PUZZLE_CORRECT";


			[