Decompiled source of BetterVanilla v1.1.10

BetterVanilla.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using AmongUs.Data;
using AmongUs.GameOptions;
using AmongUsDevKit.LibraryRuntime;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Utils;
using BetterVanilla.Components;
using BetterVanilla.Components.BaseComponents;
using BetterVanilla.Components.Menu;
using BetterVanilla.Components.Menu.Outfits;
using BetterVanilla.Components.Menu.Settings;
using BetterVanilla.Core;
using BetterVanilla.Core.Attributes;
using BetterVanilla.Core.Data;
using BetterVanilla.Core.Data.Legacy;
using BetterVanilla.Core.Extensions;
using BetterVanilla.Core.Helpers;
using BetterVanilla.Core.Options;
using Cpp2IL.Core.Extensions;
using HarmonyLib;
using Hazel;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppInterop.Runtime.InteropTypes.Fields;
using Il2CppSystem;
using Il2CppSystem.Collections;
using Il2CppSystem.Collections.Generic;
using InnerNet;
using Innersloth.Assets;
using Microsoft.CodeAnalysis;
using MonoMod.Utils;
using TMPro;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BetterVanilla.Mono")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Enhanced Among Us Vanilla experience")]
[assembly: AssemblyFileVersion("1.1.10.0")]
[assembly: AssemblyInformationalVersion("1.1.10+4cb6b6ae300f2f9f8c8148ae17b86d8a7f22a57d")]
[assembly: AssemblyProduct("BetterVanilla.Mono")]
[assembly: AssemblyTitle("BetterVanilla.Mono")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.10.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BetterVanilla
{
	[BepInPlugin("bettervanilla.eno.pm", "BetterVanilla", "1.1.10")]
	public class BetterVanillaPlugin : BasePlugin
	{
		public override void Load()
		{
			MainInterop.__m_K5zv8eLaRFhl0AIeb8k3Rn1N44spwTNr0u();
			Ls.SetLogSource(((BasePlugin)this).Log);
			((BasePlugin)this).AddComponent<BetterVanillaManager>();
		}
	}
}
namespace BetterVanilla.Compiler
{
	internal static class GeneratedProps
	{
		public const string Guid = "bettervanilla.eno.pm";

		public const string Name = "BetterVanilla";

		public const string Version = "1.1.10";
	}
}
namespace BetterVanilla.Core
{
	public sealed class BetterRoleAssignments
	{
		private const int BaseWeight = 100;

		private const int PenaltyForNonPreferredTeam = 15;

		private const int BonusForForcedAssignment = 200;

		private readonly IGameOptions _currentOptions;

		private readonly int _numImpostors;

		private readonly List<PlayerControl> _allPlayers = new List<PlayerControl>();

		private readonly List<PlayerControl> _remainingPlayers = new List<PlayerControl>();

		private readonly Dictionary<int, TeamPreferences> _playerPreferences = new Dictionary<int, TeamPreferences>();

		private readonly Dictionary<int, TeamPreferences> _playerForcedAssignments = new Dictionary<int, TeamPreferences>();

		private readonly List<RoleTypes> _allCrewmateRoles = new List<RoleTypes>();

		private readonly List<RoleTypes> _allImpostorRoles = new List<RoleTypes>();

		public BetterRoleAssignments()
		{
			Enumerator<PlayerControl> enumerator = PlayerControl.AllPlayerControls.GetEnumerator();
			while (enumerator.MoveNext())
			{
				PlayerControl current = enumerator.Current;
				if (Object.op_Implicit((Object)(object)current) && Object.op_Implicit((Object)(object)current.Data) && !current.Data.Disconnected && !current.Data.IsDead)
				{
					_allPlayers.Add(current);
				}
			}
			_currentOptions = GameOptionsManager.Instance.CurrentGameOptions;
			_numImpostors = IGameOptionsExtensions.GetAdjustedNumImpostors(GameOptionsManager.Instance.CurrentGameOptions, _allPlayers.Count);
			_remainingPlayers.AddRange(_allPlayers);
			SetupRoles();
		}

		public void SetTeamPreference(int playerId, TeamPreferences preference)
		{
			_playerPreferences[playerId] = preference;
		}

		public void SetTeamPreferences(Dictionary<int, TeamPreferences> preferences)
		{
			foreach (KeyValuePair<int, TeamPreferences> preference in preferences)
			{
				SetTeamPreference(preference.Key, preference.Value);
			}
		}

		public void SetForcedAssignment(int playerId, TeamPreferences preference)
		{
			_playerForcedAssignments[playerId] = preference;
		}

		public void SetForcedAssignments(Dictionary<int, TeamPreferences> preferences)
		{
			foreach (KeyValuePair<int, TeamPreferences> preference in preferences)
			{
				SetForcedAssignment(preference.Key, preference.Value);
			}
		}

		private void SetupRoles()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Invalid comparison between Unknown and I4
			//IL_0070: 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)
			IRoleOptionsCollection roleOptions = _currentOptions.RoleOptions;
			foreach (RoleBehaviour item in (Il2CppArrayBase<RoleBehaviour>)(object)DestroyableSingleton<RoleManager>.Instance.AllRoles)
			{
				RoleTeamTypes teamType = item.TeamType;
				RoleTypes role = item.Role;
				int numPerGame = roleOptions.GetNumPerGame(role);
				int chancePerGame = roleOptions.GetChancePerGame(role);
				if (chancePerGame == 0 || numPerGame == 0)
				{
					continue;
				}
				bool flag = chancePerGame < 100;
				for (int i = 0; i < numPerGame; i++)
				{
					if (!flag || HashRandom.Next(101) < chancePerGame)
					{
						if ((int)teamType == 0)
						{
							_allCrewmateRoles.Add(role);
						}
						else if ((int)teamType == 1)
						{
							_allImpostorRoles.Add(role);
						}
					}
				}
			}
		}

		private Dictionary<byte, int> CalculateWeights(RoleTeamTypes team, bool ignorePlayerPreferences = false)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<byte, int> dictionary = new Dictionary<byte, int>();
			TeamPreferences teamPreferences = ConvertRoleTeamTypeToTeamPreference(team);
			TeamPreferences? opposite = GetOpposite(teamPreferences);
			foreach (PlayerControl remainingPlayer in _remainingPlayers)
			{
				TeamPreferences forcedAssignmentForPlayer = GetForcedAssignmentForPlayer(remainingPlayer);
				byte playerId = remainingPlayer.PlayerId;
				TeamPreferences preferenceForPlayer = GetPreferenceForPlayer(remainingPlayer);
				int num = 100;
				if (!ignorePlayerPreferences && preferenceForPlayer != TeamPreferences.Both && preferenceForPlayer != teamPreferences)
				{
					num -= 15;
				}
				if (forcedAssignmentForPlayer != TeamPreferences.Both)
				{
					num = ((forcedAssignmentForPlayer != opposite) ? 200 : 0);
				}
				if (num > 0)
				{
					dictionary[playerId] = num;
				}
			}
			return dictionary;
		}

		private List<PlayerControl> PickRandomPlayersBasedOnWeights(Dictionary<byte, int> weights, int amount)
		{
			List<PlayerControl> list = new List<PlayerControl>();
			Dictionary<byte, int> dictionary = Enumerable.ToDictionary(weights, (KeyValuePair<byte, int> entry) => entry.Key, (KeyValuePair<byte, int> entry) => entry.Value);
			for (int i = 0; i < amount; i++)
			{
				if (dictionary.Count == 0)
				{
					break;
				}
				int num = Enumerable.Sum(dictionary.Values);
				int num2 = Random.Range(0, num);
				byte selectedPlayerId = 0;
				foreach (byte key in dictionary.Keys)
				{
					if (num2 < dictionary[key])
					{
						selectedPlayerId = key;
						break;
					}
					num2 -= dictionary[key];
				}
				PlayerControl item = Enumerable.First(_remainingPlayers, (PlayerControl x) => x.PlayerId == selectedPlayerId);
				list.Add(item);
				_remainingPlayers.Remove(item);
				dictionary.Remove(selectedPlayerId);
			}
			return list;
		}

		private List<PlayerControl> GetTeam(RoleTeamTypes teamType, int teamSize)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<byte, int> weights = CalculateWeights(teamType, !BetterVanillaManager.Instance.HostOptions.AllowTeamPreference.GetBool());
			return PickRandomPlayersBasedOnWeights(weights, teamSize);
		}

		private static Dictionary<PlayerControl, RoleTypes> GetRolesAssignation(List<PlayerControl> players, List<RoleTypes> roles, RoleTypes defaultRole)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<PlayerControl, RoleTypes> dictionary = new Dictionary<PlayerControl, RoleTypes>();
			foreach (PlayerControl player in players)
			{
				RoleTypes value = ((roles.Count > 0) ? roles.PickOneRandom() : defaultRole);
				dictionary.Add(player, value);
			}
			return dictionary;
		}

		public void StartAssignation()
		{
			int teamSize = Mathf.Max(1, _numImpostors);
			List<PlayerControl> team = GetTeam((RoleTeamTypes)1, teamSize);
			int count = _remainingPlayers.Count;
			List<PlayerControl> team2 = GetTeam((RoleTeamTypes)0, count);
			Dictionary<PlayerControl, RoleTypes> dictionary = new Dictionary<PlayerControl, RoleTypes>();
			Extensions.AddRange<PlayerControl, RoleTypes>(dictionary, GetRolesAssignation(team, _allImpostorRoles, (RoleTypes)1));
			Extensions.AddRange<PlayerControl, RoleTypes>(dictionary, GetRolesAssignation(team2, _allCrewmateRoles, (RoleTypes)0));
			SendRolesAssignation(dictionary);
		}

		private static void SendRolesAssignation(Dictionary<PlayerControl, RoleTypes> playerRoles)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			foreach (var (val3, val4) in playerRoles)
			{
				val3.RpcSetRole(val4, false);
			}
		}

		private TeamPreferences GetPreferenceForPlayer(PlayerControl player)
		{
			return CollectionExtensions.GetValueOrDefault(_playerPreferences, ((InnerNetObject)player).OwnerId, TeamPreferences.Both);
		}

		private TeamPreferences GetForcedAssignmentForPlayer(PlayerControl player)
		{
			return CollectionExtensions.GetValueOrDefault(_playerForcedAssignments, ((InnerNetObject)player).OwnerId, TeamPreferences.Both);
		}

		private static TeamPreferences ConvertRoleTeamTypeToTeamPreference(RoleTeamTypes teamType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Invalid comparison between Unknown and I4
			if ((int)teamType != 0)
			{
				if ((int)teamType == 1)
				{
					return TeamPreferences.Impostor;
				}
				throw new ArgumentOutOfRangeException("teamType", "Unable to find Preference correspondence for " + ((object)(RoleTeamTypes)(ref teamType)).ToString());
			}
			return TeamPreferences.Crewmate;
		}

		private static TeamPreferences? GetOpposite(TeamPreferences preference)
		{
			return preference switch
			{
				TeamPreferences.Crewmate => TeamPreferences.Impostor, 
				TeamPreferences.Impostor => TeamPreferences.Crewmate, 
				_ => null, 
			};
		}
	}
	public sealed class ChatCommandsManager
	{
		private const string CommandPrefix = "/";

		private readonly Dictionary<string, Func<List<string>, bool>> _commands = new Dictionary<string, Func<List<string>, bool>>
		{
			{ "kick", KickCommandHandler },
			{ "ban", BanCommandHandler },
			{ "tp", TpCommandHandler },
			{ "w", WhisperCommandHandler },
			{ "r", ReplyCommandHandler }
		};

		private static string LastPrivateMessageSenderName { get; set; }

		public bool IsChatCommand(string message)
		{
			return message.StartsWith("/");
		}

		public bool ExecuteCommand(string message)
		{
			int length = "/".Length;
			List<string> list = Enumerable.ToList(message.Substring(length, message.Length - length).Split(" "));
			if (_commands.TryGetValue(list[0].ToLowerInvariant().Trim(), out var value))
			{
				list.RemoveAt(0);
				value(list);
				return true;
			}
			return false;
		}

		public static void HandlePrivateMessageRpc(PlayerControl sender, MessageReader reader)
		{
			int targetOwnerId = reader.ReadInt32();
			PlayerControl val = Enumerable.FirstOrDefault((IEnumerable<PlayerControl>)PlayerControl.AllPlayerControls.ToArray(), (Func<PlayerControl, bool>)((PlayerControl x) => ((InnerNetObject)x).OwnerId == targetOwnerId && (Object)(object)x.Data != (Object)null));
			if (!((Object)(object)val == (Object)null) && ((InnerNetObject)val).OwnerId == ((InnerNetObject)PlayerControl.LocalPlayer).OwnerId)
			{
				LastPrivateMessageSenderName = sender.Data.PlayerName;
				string chatText = reader.ReadString();
				DestroyableSingleton<HudManager>.Instance.Chat.AddPrivateChat(sender, val, chatText);
			}
		}

		private static bool KickCommandHandler(List<string> arguments)
		{
			if (arguments.Count == 0)
			{
				return false;
			}
			string playerName = string.Join(" ", arguments);
			PlayerControl val = Enumerable.FirstOrDefault((IEnumerable<PlayerControl>)PlayerControl.AllPlayerControls.ToArray(), (Func<PlayerControl, bool>)((PlayerControl x) => x.Data.PlayerName.Equals(playerName)));
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)AmongUsClient.Instance) || !((InnerNetClient)AmongUsClient.Instance).CanBan())
			{
				return false;
			}
			ClientData client = ((InnerNetClient)AmongUsClient.Instance).GetClient(((InnerNetObject)val).OwnerId);
			if (client == null)
			{
				return false;
			}
			((InnerNetClient)AmongUsClient.Instance).KickPlayer(client.Id, false);
			return true;
		}

		private static bool BanCommandHandler(List<string> arguments)
		{
			if (arguments.Count == 0)
			{
				return false;
			}
			string playerName = string.Join(" ", arguments);
			PlayerControl val = Enumerable.FirstOrDefault((IEnumerable<PlayerControl>)PlayerControl.AllPlayerControls.ToArray(), (Func<PlayerControl, bool>)((PlayerControl x) => x.Data.PlayerName.Equals(playerName)));
			if ((Object)(object)val == (Object)null || (Object)(object)AmongUsClient.Instance == (Object)null || !((InnerNetClient)AmongUsClient.Instance).CanBan())
			{
				return false;
			}
			ClientData client = ((InnerNetClient)AmongUsClient.Instance).GetClient(((InnerNetObject)val).OwnerId);
			if (client == null)
			{
				return false;
			}
			((InnerNetClient)AmongUsClient.Instance).KickPlayer(client.Id, true);
			return true;
		}

		private static bool TpCommandHandler(List<string> arguments)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (arguments.Count == 0 || !LocalConditions.AmDead() || Object.op_Implicit((Object)(object)MeetingHud.Instance))
			{
				return false;
			}
			string playerName = string.Join(" ", arguments);
			PlayerControl val = Enumerable.FirstOrDefault((IEnumerable<PlayerControl>)PlayerControl.AllPlayerControls.ToArray(), (Func<PlayerControl, bool>)((PlayerControl x) => x.Data.PlayerName.Equals(playerName)));
			if (!Object.op_Implicit((Object)(object)val))
			{
				return false;
			}
			((Component)PlayerControl.LocalPlayer).transform.position = ((Component)val).transform.position;
			return true;
		}

		private static bool WhisperCommandHandler(List<string> arguments)
		{
			if (arguments.Count == 0)
			{
				return false;
			}
			string rawMessage = string.Join(" ", arguments);
			PlayerControl val = Enumerable.MinBy(Enumerable.Where((IEnumerable<PlayerControl>)PlayerControl.AllPlayerControls.ToArray(), (PlayerControl x) => rawMessage.ToLowerInvariant().StartsWith(x.Data.PlayerName.ToLowerInvariant())), delegate(PlayerControl x)
			{
				string text2 = rawMessage;
				int length = x.Data.PlayerName.Length;
				return text2.Substring(length, text2.Length - length).Length;
			});
			if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)AmongUsClient.Instance))
			{
				return false;
			}
			string text = rawMessage;
			int num = val.Data.PlayerName.Length + 1;
			string message = text.Substring(num, text.Length - num);
			PlayerControl.LocalPlayer.RpcSendPrivateMessage(val, message);
			return true;
		}

		private static bool ReplyCommandHandler(List<string> arguments)
		{
			if (arguments.Count == 0 || LastPrivateMessageSenderName == string.Empty)
			{
				return false;
			}
			return WhisperCommandHandler(Enumerable.ToList((LastPrivateMessageSenderName + " " + string.Join(" ", arguments)).Split(" ")));
		}
	}
	public sealed class CheatersManager
	{
		public readonly Dictionary<byte, string> SickoUsers = new Dictionary<byte, string>();

		public readonly Dictionary<byte, string> AumUsers = new Dictionary<byte, string>();

		public bool IsCheating(BetterPlayerControl player)
		{
			return IsCheating(player.Player);
		}

		public bool IsCheating(PlayerControl player)
		{
			byte playerId = player.PlayerId;
			if (!SickoUsers.ContainsKey(playerId))
			{
				return AumUsers.ContainsKey(playerId);
			}
			return true;
		}

		public void HandleRpc(PlayerControl sender, byte callId, MessageReader reader)
		{
			HandleSicko(sender, callId, reader);
			HandleAum(sender, callId, reader);
		}

		private void HandleSicko(PlayerControl player, byte callId, MessageReader reader)
		{
			if (callId == 164 && reader.BytesRemaining == 0 && !IsCheating(player))
			{
				player.ReportPlayer((ReportReasons)2);
				SickoUsers.Add(player.PlayerId, player.FriendCode);
			}
		}

		private void HandleAum(PlayerControl player, byte callId, MessageReader reader)
		{
			if (callId != 85 && callId != 101)
			{
				return;
			}
			if (callId == 101)
			{
				try
				{
					string text = reader.ReadString();
					if (player.Data.PlayerName != text)
					{
						throw new Exception();
					}
				}
				catch
				{
					return;
				}
			}
			if (!IsCheating(player))
			{
				AumUsers.Add(player.PlayerId, player.FriendCode);
			}
		}
	}
	public sealed class DatabaseManager
	{
		public readonly LocalData Data;

		private readonly string _filePath;

		public DatabaseManager()
		{
			string directoryName = Path.GetDirectoryName(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData));
			if (directoryName == null)
			{
				throw new Exception("Unable to locate appData directory");
			}
			string text = Path.Combine(directoryName, "LocalLow", Application.companyName, Application.productName, "BetterVanilla");
			if (!Directory.Exists(text))
			{
				Directory.CreateDirectory(text);
			}
			_filePath = Path.Combine(text, "db.dat");
			if (!File.Exists(_filePath))
			{
				Data = new LocalData();
			}
			else
			{
				Data = JsonSerializer.Deserialize<LocalData>(File.ReadAllText(_filePath));
			}
			CheckAndMigrateLegacyDatabase(text);
		}

		public void Save()
		{
			File.WriteAllText(_filePath, JsonSerializer.Serialize(Data));
		}

		private void CheckAndMigrateLegacyDatabase(string directoryPath)
		{
			string path = Path.Combine(directoryPath, "player.dat");
			string path2 = Path.Combine(directoryPath, "outfits.dat");
			string path3 = Path.Combine(directoryPath, "settings.dat");
			if (File.Exists(path))
			{
				LegacyPlayerDatabase legacyPlayerDatabase = JsonSerializer.Deserialize<LegacyPlayerDatabase>(Encoding.UTF8.GetString(File.ReadAllBytes(path)));
				Data.PlayerExp = legacyPlayerDatabase.PlayerExp;
				Data.PlayerLevel = legacyPlayerDatabase.PlayerLevel;
				foreach (string featureCode in legacyPlayerDatabase.FeatureCodes)
				{
					Data.FeatureCodes.Add(featureCode);
				}
				Save();
				File.Delete(path);
			}
			if (File.Exists(path2))
			{
				foreach (LegacyDressingOutfit outfit in JsonSerializer.Deserialize<LegacyOutfitsDatabase>(Encoding.UTF8.GetString(File.ReadAllBytes(path2))).Outfits)
				{
					Data.Outfits.Add(new LocalOutfitData
					{
						Hat = outfit.Hat,
						Skin = outfit.Skin,
						Visor = outfit.Visor,
						Pet = outfit.Pet,
						Nameplate = outfit.Nameplate
					});
				}
				Save();
				File.Delete(path2);
			}
			if (File.Exists(path3))
			{
				File.Delete(path3);
			}
		}
	}
	public sealed class FeaturesManager
	{
		private readonly HashSet<string> _availableHashes = new HashSet<string>();

		private readonly HashSet<string> _hashedCodes = new HashSet<string>();

		public FeaturesRegistry Registry { get; private set; }

		public FeaturesManager()
		{
			foreach (string featureCode in BetterVanillaManager.Instance.Database.Data.FeatureCodes)
			{
				_hashedCodes.Add(StringUtils.CalculateSHA256(featureCode));
			}
		}

		public void RegisterHash(string hash)
		{
			_availableHashes.Add(hash);
		}

		public void Initialize(string githubRepository, string branchName, string filePath)
		{
			MonoBehaviourExtensions.StartCoroutine((MonoBehaviour)(object)BetterVanillaManager.Instance, CoStart(githubRepository, branchName, filePath));
		}

		private IEnumerator CoStart(string githubRepository, string branchName, string filePath)
		{
			UnityWebRequest www = new UnityWebRequest();
			www.SetMethod((UnityWebRequestMethod)0);
			www.SetUrl($"https://raw.githubusercontent.com/{githubRepository}/refs/heads/{branchName}/{filePath}");
			www.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
			UnityWebRequestAsyncOperation operation = www.SendWebRequest();
			while (!((AsyncOperation)operation).isDone)
			{
				yield return null;
			}
			if (www.isNetworkError || www.isHttpError)
			{
				Ls.LogError((object)www.error);
				yield break;
			}
			Registry = JsonSerializer.Deserialize<FeaturesRegistry>(www.downloadHandler.text);
			www.downloadHandler.Dispose();
			www.Dispose();
			if (Registry == null)
			{
				Ls.LogError((object)"No features registry found");
			}
		}

		public void RegisterCode(string featureCode)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			string text = StringUtils.CalculateSHA256(featureCode);
			bool flag = default(bool);
			BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(31, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Trying to register code: ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(featureCode);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" => [");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("]");
			}
			Ls.LogInfo(val);
			if (!_availableHashes.Contains(text) || !IsUnlockable(text))
			{
				return;
			}
			if (!BetterVanillaManager.Instance.Database.Data.FeatureCodes.Add(featureCode))
			{
				val = new BepInExErrorLogInterpolatedStringHandler(15, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Removing hash: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
				}
				Ls.LogInfo(val);
				BetterVanillaManager.Instance.Database.Data.FeatureCodes.Remove(featureCode);
				_hashedCodes.Remove(text);
			}
			else
			{
				val = new BepInExErrorLogInterpolatedStringHandler(12, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Added hash: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
				}
				Ls.LogInfo(val);
				_hashedCodes.Add(text);
			}
			BetterVanillaManager.Instance.Database.Save();
		}

		private bool IsUnlockable(string hash)
		{
			EOSManager instance = DestroyableSingleton<EOSManager>.Instance;
			if (Registry == null || !Object.op_Implicit((Object)(object)instance) || string.IsNullOrEmpty(instance.FriendCode))
			{
				return false;
			}
			if (!Registry.FeatureHashPermissions.TryGetValue(hash, out var value))
			{
				return false;
			}
			if (!value.Contains(instance.FriendCode))
			{
				return false;
			}
			return true;
		}

		public bool IsUnlocked(string hash)
		{
			if (_hashedCodes.Contains(hash))
			{
				return IsUnlockable(hash);
			}
			return false;
		}

		public bool IsLocked(string hash)
		{
			return !IsUnlocked(hash);
		}
	}
	public static class GameEventManager
	{
		public static event Action MeetingStarted;

		public static event Action<PlayerControl> MeetingEnded;

		public static event Action GameStarted;

		public static event Action GameEnded;

		public static event Action<PlayerControl> PlayerJoined;

		public static event Action<PlayerControl> PlayerReady;

		public static void TriggerMeetingStarted()
		{
			GameEventManager.MeetingStarted?.Invoke();
		}

		public static void TriggerMeetingEnded(PlayerControl exiledPlayer)
		{
			GameEventManager.MeetingEnded?.Invoke(exiledPlayer);
		}

		public static void TriggerGameStarted()
		{
			GameEventManager.GameStarted?.Invoke();
		}

		public static void TriggerGameEnded()
		{
			GameEventManager.GameEnded?.Invoke();
		}

		public static void TriggerPlayerJoined(PlayerControl player)
		{
			GameEventManager.PlayerJoined?.Invoke(player);
		}

		public static void TriggerPlayerReady(PlayerControl player)
		{
			GameEventManager.PlayerReady?.Invoke(player);
		}
	}
	public sealed class HostOptionsHolder
	{
		private readonly HostCategory _category;

		public readonly BoolHostOption AllowDeadVoteDisplay;

		public readonly BoolHostOption AllowTeamPreference;

		public readonly FloatHostOption PolusReactorCountdown;

		public HostOptionsHolder()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			_category = new HostCategory("Better Vanilla");
			AllowDeadVoteDisplay = _category.CreateBool("DeadVoteDisplayAllowed", "Allow realtime vote display", defaultValue: true);
			AllowTeamPreference = _category.CreateBool("TeamPreferenceAllowed", "Allow Team Preferences", defaultValue: true);
			PolusReactorCountdown = _category.CreateFloat("PolusReactorCountdown", "Polus Reactor Countdown", 60f, 0.5f, new FloatRange(15f, 120f), "0.0", zeroIsInfinity: false, (NumberSuffixes)2);
		}

		public void ShareAllOptions()
		{
			if (!((InnerNetClient)AmongUsClient.Instance).AmHost)
			{
				return;
			}
			foreach (BaseHostOption allOption in _category.AllOptions)
			{
				PlayerControl.LocalPlayer.RpcShareHostOption(allOption);
			}
		}
	}
	public sealed class LegacyBetterRoleAssignments
	{
		private const int TicketsPerPlayer = 20;

		private const int TicketsPenaltyForNonPreferredTeam = 15;

		private readonly IGameOptions _currentOptions;

		private readonly int _numImpostors;

		private readonly List<PlayerControl> _allPlayers = new List<PlayerControl>();

		private readonly List<PlayerControl> _remainingPlayers = new List<PlayerControl>();

		private readonly Dictionary<byte, TeamPreferences> _playerPreferences = new Dictionary<byte, TeamPreferences>();

		private readonly Dictionary<byte, TeamPreferences> _playerForcedAssignments = new Dictionary<byte, TeamPreferences>();

		private readonly List<RoleTypes> _allCrewmateRoles = new List<RoleTypes>();

		private readonly List<RoleTypes> _allImpostorRoles = new List<RoleTypes>();

		public LegacyBetterRoleAssignments()
		{
			Enumerator<PlayerControl> enumerator = PlayerControl.AllPlayerControls.GetEnumerator();
			while (enumerator.MoveNext())
			{
				PlayerControl current = enumerator.Current;
				if (Object.op_Implicit((Object)(object)current) && Object.op_Implicit((Object)(object)current.Data) && !current.Data.Disconnected && !current.Data.IsDead)
				{
					_allPlayers.Add(current);
				}
			}
			_currentOptions = GameOptionsManager.Instance.CurrentGameOptions;
			_numImpostors = IGameOptionsExtensions.GetAdjustedNumImpostors(GameOptionsManager.Instance.CurrentGameOptions, _allPlayers.Count);
			_remainingPlayers.AddRange(_allPlayers);
			SetupRoles();
		}

		public void SetTeamPreference(byte playerId, TeamPreferences preference)
		{
			_playerPreferences[playerId] = preference;
		}

		public void SetTeamPreferences(Dictionary<byte, TeamPreferences> preferences)
		{
			foreach (KeyValuePair<byte, TeamPreferences> preference in preferences)
			{
				SetTeamPreference(preference.Key, preference.Value);
			}
		}

		public void SetForcedAssignment(byte playerId, TeamPreferences preference)
		{
			_playerForcedAssignments[playerId] = preference;
		}

		public void SetForcedAssignments(Dictionary<byte, TeamPreferences> preferences)
		{
			foreach (KeyValuePair<byte, TeamPreferences> preference in preferences)
			{
				SetForcedAssignment(preference.Key, preference.Value);
			}
		}

		private void SetupRoles()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Invalid comparison between Unknown and I4
			//IL_0070: 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)
			IRoleOptionsCollection roleOptions = _currentOptions.RoleOptions;
			foreach (RoleBehaviour item in (Il2CppArrayBase<RoleBehaviour>)(object)DestroyableSingleton<RoleManager>.Instance.AllRoles)
			{
				RoleTeamTypes teamType = item.TeamType;
				RoleTypes role = item.Role;
				int numPerGame = roleOptions.GetNumPerGame(role);
				int chancePerGame = roleOptions.GetChancePerGame(role);
				if (chancePerGame == 0 || numPerGame == 0)
				{
					continue;
				}
				bool flag = chancePerGame < 100;
				for (int i = 0; i < numPerGame; i++)
				{
					if (!flag || HashRandom.Next(101) < chancePerGame)
					{
						if ((int)teamType == 0)
						{
							_allCrewmateRoles.Add(role);
						}
						else if ((int)teamType == 1)
						{
							_allImpostorRoles.Add(role);
						}
					}
				}
			}
		}

		private List<byte> CreateDraw(RoleTeamTypes team, bool ignorePlayerPreferences = false)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			List<byte> list = new List<byte>();
			TeamPreferences teamPreferences = ConvertRoleTeamTypeToTeamPreference(team);
			TeamPreferences? opposite = GetOpposite(teamPreferences);
			foreach (PlayerControl remainingPlayer in _remainingPlayers)
			{
				TeamPreferences forcedAssignmentForPlayer = GetForcedAssignmentForPlayer(remainingPlayer);
				byte playerId = remainingPlayer.PlayerId;
				int num = 20;
				TeamPreferences preferenceForPlayer = GetPreferenceForPlayer(remainingPlayer);
				if (!ignorePlayerPreferences && preferenceForPlayer != TeamPreferences.Both && preferenceForPlayer != teamPreferences)
				{
					num -= 15;
				}
				if (forcedAssignmentForPlayer == TeamPreferences.Both || forcedAssignmentForPlayer != opposite)
				{
					for (int i = 0; i < num; i++)
					{
						list.Add(playerId);
					}
				}
			}
			return list;
		}

		private TeamPreferences GetPreferenceForPlayer(PlayerControl player)
		{
			return CollectionExtensions.GetValueOrDefault(_playerPreferences, player.PlayerId, TeamPreferences.Both);
		}

		private TeamPreferences GetForcedAssignmentForPlayer(PlayerControl player)
		{
			return CollectionExtensions.GetValueOrDefault(_playerForcedAssignments, player.PlayerId, TeamPreferences.Both);
		}

		private static TeamPreferences ConvertRoleTeamTypeToTeamPreference(RoleTeamTypes teamType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Invalid comparison between Unknown and I4
			if ((int)teamType != 0)
			{
				if ((int)teamType == 1)
				{
					return TeamPreferences.Impostor;
				}
				throw new ArgumentOutOfRangeException("teamType", "Unable to find Preference correspondence for " + ((object)(RoleTeamTypes)(ref teamType)).ToString());
			}
			return TeamPreferences.Crewmate;
		}

		private static TeamPreferences? GetOpposite(TeamPreferences preference)
		{
			return preference switch
			{
				TeamPreferences.Crewmate => TeamPreferences.Impostor, 
				TeamPreferences.Impostor => TeamPreferences.Crewmate, 
				_ => null, 
			};
		}

		private List<PlayerControl> PickRandomPlayersFromDraw(List<byte> draw, int amount)
		{
			List<PlayerControl> list = new List<PlayerControl>();
			for (int i = 0; i < amount; i++)
			{
				if (draw.Count == 0)
				{
					return list;
				}
				byte playerId = draw.PickOneRandom();
				PlayerControl item = Enumerable.First(_remainingPlayers, (PlayerControl x) => x.PlayerId == playerId);
				list.Add(item);
				_remainingPlayers.Remove(item);
				while (draw.Contains(playerId))
				{
					draw.Remove(playerId);
				}
			}
			return list;
		}

		private List<PlayerControl> GetTeam(RoleTeamTypes teamType, int teamSize)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			List<byte> draw = CreateDraw(teamType, !BetterVanillaManager.Instance.HostOptions.AllowTeamPreference.GetBool());
			return PickRandomPlayersFromDraw(draw, teamSize);
		}

		private static Dictionary<PlayerControl, RoleTypes> GetRolesAssignation(List<PlayerControl> players, List<RoleTypes> roles, RoleTypes defaultRole)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<PlayerControl, RoleTypes> dictionary = new Dictionary<PlayerControl, RoleTypes>();
			foreach (PlayerControl player in players)
			{
				RoleTypes value = ((roles.Count > 0) ? roles.PickOneRandom() : defaultRole);
				dictionary.Add(player, value);
			}
			return dictionary;
		}

		public void StartAssignation()
		{
			int teamSize = Mathf.Max(1, _numImpostors);
			List<PlayerControl> team = GetTeam((RoleTeamTypes)1, teamSize);
			int count = _remainingPlayers.Count;
			List<PlayerControl> team2 = GetTeam((RoleTeamTypes)0, count);
			Dictionary<PlayerControl, RoleTypes> dictionary = new Dictionary<PlayerControl, RoleTypes>();
			Extensions.AddRange<PlayerControl, RoleTypes>(dictionary, GetRolesAssignation(team, _allImpostorRoles, (RoleTypes)1));
			Extensions.AddRange<PlayerControl, RoleTypes>(dictionary, GetRolesAssignation(team2, _allCrewmateRoles, (RoleTypes)0));
			SendRolesAssignation(dictionary);
		}

		private static void SendRolesAssignation(Dictionary<PlayerControl, RoleTypes> playerRoles)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			foreach (var (val3, val4) in playerRoles)
			{
				val3.RpcSetRole(val4, false);
			}
		}
	}
	public static class LocalConditions
	{
		private static readonly List<Modes> AllowedRevealMapModes = new List<Modes>(2)
		{
			(Modes)1,
			(Modes)3
		};

		public static LocalOptionsHolder Options => BetterVanillaManager.Instance.LocalOptions;

		public static bool ShouldAutoPlayAgain()
		{
			return Options.AutoPlayAgain.Value;
		}

		public static bool ShouldShowRolesAndTasks()
		{
			return Options.DisplayRolesAndTasksAfterDeath.Value;
		}

		public static bool ShouldShowRolesAndTasks(PlayerControl playerControl)
		{
			if (ShouldShowRolesAndTasks() && IsGameStarted())
			{
				if (!((Object)(object)PlayerControl.LocalPlayer == (Object)(object)playerControl))
				{
					return AmDead();
				}
				return true;
			}
			return false;
		}

		public static bool AmDead()
		{
			if (Options.DisableAmDeadCheck.IsLocked() || !BetterVanillaManager.Instance.LocalOptions.DisableAmDeadCheck.Value)
			{
				if (Object.op_Implicit((Object)(object)PlayerControl.LocalPlayer) && Object.op_Implicit((Object)(object)PlayerControl.LocalPlayer.Data))
				{
					return PlayerControl.LocalPlayer.Data.IsDead;
				}
				return false;
			}
			return true;
		}

		public static bool AmImpostor()
		{
			if (Options.DisableAmImpostorCheck.IsLocked() || !Options.DisableAmImpostorCheck.Value)
			{
				if (Object.op_Implicit((Object)(object)PlayerControl.LocalPlayer) && Object.op_Implicit((Object)(object)PlayerControl.LocalPlayer.Data) && Object.op_Implicit((Object)(object)PlayerControl.LocalPlayer.Data.Role))
				{
					return PlayerControl.LocalPlayer.Data.Role.IsImpostor;
				}
				return false;
			}
			return false;
		}

		public static bool AmAlive()
		{
			return !AmDead();
		}

		public static bool IsGameStarted()
		{
			if (Object.op_Implicit((Object)(object)AmongUsClient.Instance))
			{
				if (!((InnerNetClient)AmongUsClient.Instance).IsGameStarted)
				{
					return DestroyableSingleton<TutorialManager>.InstanceExists;
				}
				return true;
			}
			return false;
		}

		public static bool IsIncrementMultiplierKeyPressed()
		{
			if (!Input.GetKey((KeyCode)304))
			{
				return Input.GetKey((KeyCode)303);
			}
			return true;
		}

		public static bool ShouldRevealPlayerPositionsInMap(Modes currentMapMode)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (AllowedRevealMapModes.Contains(currentMapMode) && Options.DisplayPlayersInMapAfterDeath.Value && !Object.op_Implicit((Object)(object)MeetingHud.Instance) && AmDead())
			{
				return !AmImpostor();
			}
			return false;
		}

		public static bool ShouldRevealVotes()
		{
			if (Options.DisplayVotesAfterDeath.Value)
			{
				return AmDead();
			}
			return false;
		}

		public static bool ShouldRevealVoteColors()
		{
			if (Options.DisplayVoteColorsAfterDeath.Value)
			{
				return AmDead();
			}
			return false;
		}

		public static bool IsForcedTeamAssignmentAllowed()
		{
			return !Options.ForcedTeamAssignment.IsLocked();
		}

		public static bool CanZoom()
		{
			if (Object.op_Implicit((Object)(object)BetterVanillaManager.Instance.ZoomBehaviour) && AmDead())
			{
				return !AmImpostor();
			}
			return false;
		}

		public static bool ShouldDisableGameStartRequirement()
		{
			if (!Options.DisableGameStartRequirement.IsLocked())
			{
				return Options.DisableGameStartRequirement.Value;
			}
			return false;
		}

		public static bool ShouldDisableGameEndRequirement()
		{
			if (!Options.DisableEndGameChecks.IsLocked())
			{
				return Options.DisableEndGameChecks.Value;
			}
			return false;
		}

		public static bool ShouldUnlockModdedCosmetics()
		{
			if (!Options.AllowModdedCosmetics.IsLocked())
			{
				return Options.AllowModdedCosmetics.Value;
			}
			return false;
		}

		public static bool ShouldRevealVentPositionsInMap()
		{
			return Options.DisplayVentsInMap.Value;
		}
	}
	public sealed class LocalOptionsHolder
	{
		public readonly BoolLocalOption DisplayVentsInMap;

		public readonly BoolLocalOption DisplayRolesAndTasksAfterDeath;

		public readonly BoolLocalOption DisplayPlayersInMapAfterDeath;

		public readonly BoolLocalOption DisplayVotesAfterDeath;

		public readonly BoolLocalOption DisplayVoteColorsAfterDeath;

		public readonly BoolLocalOption AutoPlayAgain;

		public readonly StringLocalOption TeamPreference;

		public readonly BoolLocalOption AllowModdedCosmetics;

		public readonly BoolLocalOption DisableAmDeadCheck;

		public readonly BoolLocalOption DisableAmImpostorCheck;

		public readonly BoolLocalOption DisableEndGameChecks;

		public readonly BoolLocalOption DisableGameStartRequirement;

		public readonly StringLocalOption ForcedTeamAssignment;

		public LocalOptionsHolder()
		{
			LocalCategory localCategory = new LocalCategory("Local Settings");
			DisplayVentsInMap = localCategory.CreateBool("DisplayVentsInMap", "Display vents in map", defaultValue: true);
			DisplayRolesAndTasksAfterDeath = localCategory.CreateBool("DisplayRolesAndTasksAfterDeath", "Display roles and tasks after death", defaultValue: true);
			DisplayPlayersInMapAfterDeath = localCategory.CreateBool("DisplayPlayersInMapAfterDeath", "Display players in map after death", defaultValue: true);
			DisplayVotesAfterDeath = localCategory.CreateBool("DisplayVotesAfterDeath", "Display votes after death", defaultValue: true);
			DisplayVoteColorsAfterDeath = localCategory.CreateBool("DisplayVoteColorsAfterDeath", "Display vote colors after death", defaultValue: true);
			AutoPlayAgain = localCategory.CreateBool("AutoPlayAgain", "Auto Play Again", defaultValue: true);
			TeamPreference = localCategory.CreateEnum("TeamPreference", "Team Assignment Preference", TeamPreferences.Both);
			AllowModdedCosmetics = localCategory.CreateBool("AllowModdedCosmetics", "Display Modded Cosmetics", defaultValue: false);
			DisableAmDeadCheck = localCategory.CreateBool("DisableAmDeadCheck", "Disable Am Dead Check", defaultValue: false);
			DisableAmImpostorCheck = localCategory.CreateBool("DisableAmImpostorCheck", "Disable Am Impostor Check", defaultValue: false);
			DisableEndGameChecks = localCategory.CreateBool("DisableEndGameChecks", "Disable All End Game Checks", defaultValue: false);
			DisableGameStartRequirement = localCategory.CreateBool("DisableGameStartRequirement", "Disable Start Game Player Requirement", defaultValue: false);
			ForcedTeamAssignment = localCategory.CreateEnum("ForcedTeamAssignment", "Forced Team Assignment", TeamPreferences.Both);
			AllowModdedCosmetics.LockWithPassword("A617504DA5A04943DE0CF0C85FF2DA7B7C387C6B6D2950E1DF8CB8D0E4D69FCE");
			DisableAmDeadCheck.LockWithPassword("A21B151BDA9AD098622868D3B7EBB5B0BB819EBD7C25B6504BDAAE9FF1FF8C0F");
			DisableAmImpostorCheck.LockWithPassword("B640EC50173A2DAC2056F2926027D3BBDDEFB9A1468627A36164D4101519DDAA");
			DisableEndGameChecks.LockWithPassword("81133C46C6DAACD12259989C7D8D385BE47AF65385F9C3D5BFAFEDD2A5C44FD0");
			DisableGameStartRequirement.LockWithPassword("98F47935FFDEEDC0F716F87A5C332AA77222DF4EAF4FF61E1989EE95B1671B77");
			ForcedTeamAssignment.LockWithPassword("FE3C8AB240748CE91A143E7E61CA6C3D0996D55C23F8F3A7BC42A47BB26B7514");
			TeamPreference.ValueChanged += OnTeamPreferenceValueChanged;
			ForcedTeamAssignment.ValueChanged += OnForcedTeamAssignmentValueChanged;
		}

		private void OnTeamPreferenceValueChanged()
		{
			if (Object.op_Implicit((Object)(object)PlayerControl.LocalPlayer) && Object.op_Implicit((Object)(object)AmongUsClient.Instance))
			{
				PlayerControl.LocalPlayer.RpcSetTeamPreference(TeamPreference.ParseValue(TeamPreferences.Both));
			}
		}

		private void OnForcedTeamAssignmentValueChanged()
		{
			if (Object.op_Implicit((Object)(object)PlayerControl.LocalPlayer) && Object.op_Implicit((Object)(object)AmongUsClient.Instance))
			{
				PlayerControl.LocalPlayer.RpcSetForcedTeamAssignment(ForcedTeamAssignment.ParseValue(TeamPreferences.Both));
			}
		}
	}
	public static class Ls
	{
		private static ManualLogSource Logger { get; set; }

		public static void SetLogSource(ManualLogSource logSource)
		{
			Logger = logSource;
		}

		public static void LogError(object data)
		{
			Logger.LogError(data);
		}

		public static void LogError(BepInExErrorLogInterpolatedStringHandler logHandler)
		{
			Logger.LogError(logHandler);
		}

		public static void LogWarning(object data)
		{
			Logger.LogWarning(data);
		}

		public static void LogWarning(BepInExErrorLogInterpolatedStringHandler logHandler)
		{
			Logger.LogWarning((object)logHandler);
		}

		public static void LogMessage(object data)
		{
			Logger.LogMessage(data);
		}

		public static void LogMessage(BepInExErrorLogInterpolatedStringHandler logHandler)
		{
			Logger.LogMessage((object)logHandler);
		}

		public static void LogInfo(object data)
		{
			Logger.LogInfo(data);
		}

		public static void LogInfo(BepInExErrorLogInterpolatedStringHandler logHandler)
		{
			Logger.LogInfo((object)logHandler);
		}

		public static void LogDebug(object data)
		{
			Logger.LogDebug(data);
		}

		public static void LogDebug(BepInExErrorLogInterpolatedStringHandler logHandler)
		{
			Logger.LogDebug((object)logHandler);
		}
	}
	public sealed class PassiveButtonsBlocker
	{
		private static readonly List<PassiveButtonsBlocker> AllBlockers = new List<PassiveButtonsBlocker>();

		private bool _blocked;

		public static bool ShouldBlock()
		{
			return Enumerable.Any(AllBlockers, (PassiveButtonsBlocker x) => x._blocked);
		}

		public PassiveButtonsBlocker()
		{
			_blocked = false;
			AllBlockers.Add(this);
		}

		public void Block()
		{
			_blocked = true;
		}

		public void Unblock()
		{
			_blocked = false;
		}
	}
	public sealed class XpManager
	{
		private readonly float _baseXpPerLevel;

		private readonly float _exponent;

		public readonly uint MaxLevel;

		public uint OldLevel { get; private set; }

		public uint OldXpAmount { get; private set; }

		public uint GrantedXp { get; private set; }

		public uint NewXp { get; private set; }

		public uint NewLevel { get; private set; }

		public uint XpRequiredToLevelUp { get; private set; }

		public uint XpRequiredToLevelUpNextLevel { get; private set; }

		public bool LevelledUp { get; private set; }

		public XpManager()
		{
			_baseXpPerLevel = 100f;
			_exponent = 0.56f;
			MaxLevel = 200u;
		}

		public uint CalculateLevel(uint xp)
		{
			return Math.Min((uint)Math.Floor((float)Math.Pow((float)xp / _baseXpPerLevel, _exponent)), MaxLevel);
		}

		private uint CalculateXpForLevel(uint level)
		{
			if (level > MaxLevel)
			{
				return 0u;
			}
			return (uint)((double)_baseXpPerLevel * Math.Pow(level, 1.0 / (double)_exponent));
		}

		public void SetupCache(XpGrantResult xpGrantResult)
		{
			uint playerExp = BetterVanillaManager.Instance.Database.Data.PlayerExp;
			uint num = CalculateLevel(playerExp);
			uint num2 = CalculateXpForLevel(num);
			OldXpAmount = playerExp - num2;
			OldLevel = num;
			GrantedXp = xpGrantResult.GrantedXp;
			NewXp = OldXpAmount + GrantedXp;
			NewLevel = ((OldLevel == MaxLevel) ? OldLevel : (OldLevel + 1));
			XpRequiredToLevelUp = CalculateXpForLevel(NewLevel) - num2;
			XpRequiredToLevelUpNextLevel = CalculateXpForLevel(NewLevel + 1) - num2;
			LevelledUp = OldXpAmount + GrantedXp >= XpRequiredToLevelUp;
		}

		public void ApplyCache()
		{
			DatabaseManager database = BetterVanillaManager.Instance.Database;
			database.Data.PlayerExp += GrantedXp;
			database.Data.PlayerLevel = CalculateLevel(database.Data.PlayerExp);
			database.Save();
		}

		public void ClearCache()
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			bool flag = default(bool);
			BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(1, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("XpManager");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("ClearCache");
			}
			Ls.LogMessage(val);
			OldLevel = 0u;
			OldXpAmount = 0u;
			GrantedXp = 0u;
			NewXp = 0u;
			NewLevel = 0u;
			XpRequiredToLevelUp = 0u;
			XpRequiredToLevelUpNextLevel = 0u;
			LevelledUp = false;
		}
	}
}
namespace BetterVanilla.Core.Patches
{
	[HarmonyPatch(typeof(ChatController))]
	internal static class ChatControllerPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("SendFreeChat")]
		private static bool SendFreeChatPrefix(ChatController __instance)
		{
			string text = __instance.freeChatField.Text;
			if (BetterVanillaManager.Instance.ChatCommands.IsChatCommand(text))
			{
				if (BetterVanillaManager.Instance.ChatCommands.ExecuteCommand(text))
				{
					((AbstractChatInputField)__instance.freeChatField).Clear();
				}
				else
				{
					__instance.AddChatWarning("Unknown command: " + text);
				}
				return false;
			}
			ChatController.Logger.Debug(Object.op_Implicit("SendFreeChat () :: Sending message: '" + text + "'"), (Object)null);
			PlayerControl.LocalPlayer.RpcSendChat(text);
			return false;
		}
	}
	[HarmonyPatch(typeof(EndGameManager))]
	internal static class EndGameManagerPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("ShowButtons")]
		private static void ShowButtonsPostfix(EndGameManager __instance)
		{
			BetterVanillaManager instance = BetterVanillaManager.Instance;
			instance.AllTeamPreferences.Clear();
			instance.AllForcedTeamAssignments.Clear();
			instance.Menu.Close();
			__instance.Navigation.SetupPlayAgain();
		}
	}
	[HarmonyPatch(typeof(GameOptionsMenu))]
	internal static class GameOptionsMenuPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("CreateSettings")]
		private static bool CreateSettingsPrefix(GameOptionsMenu __instance)
		{
			__instance.CreateBetterSettings();
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch("ValueChanged")]
		private static bool ValueChangedPrefix(GameOptionsMenu __instance, OptionBehaviour option)
		{
			return __instance.CustomValueChanged(option);
		}
	}
	[HarmonyPatch(typeof(GameStartManager))]
	internal static class GameStartManagerPatches
	{
		private static int PlayersCount { get; set; }

		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix()
		{
			BetterVanillaManager.Instance.Cheaters.SickoUsers.Clear();
			BetterVanillaManager.Instance.Cheaters.AumUsers.Clear();
		}

		[HarmonyPostfix]
		[HarmonyPatch("ReallyBegin")]
		private static void ReallyBeginPostfix()
		{
			PlayersCount = PlayerControl.AllPlayerControls.Count;
		}

		[HarmonyPrefix]
		[HarmonyPatch("Update")]
		private static bool UpdatePrefix(GameStartManager __instance)
		{
			if (!Object.op_Implicit((Object)(object)GameData.Instance) || !Object.op_Implicit((Object)(object)GameManager.Instance))
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)AmongUsClient.Instance) || !((InnerNetClient)AmongUsClient.Instance).AmHost)
			{
				return true;
			}
			if (__instance.LastPlayerCount != PlayersCount)
			{
				PlayersCount = __instance.LastPlayerCount;
			}
			int minPlayers = __instance.MinPlayers;
			__instance.MinPlayers = (LocalConditions.ShouldDisableGameStartRequirement() ? 1 : 4);
			if (minPlayers != __instance.MinPlayers)
			{
				int lastPlayerCount = __instance.LastPlayerCount;
				__instance.LastPlayerCount = lastPlayerCount - 1;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(HudManager))]
	internal static class HudManagerPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix(HudManager __instance)
		{
			((Component)__instance).gameObject.AddComponent<ZoomBehaviourManager>();
			((Component)__instance).gameObject.AddComponent<TaskFinisherBehaviour>();
		}
	}
	[HarmonyPatch(typeof(LobbyViewSettingsPane))]
	internal static class LobbyViewSettingsPanePatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("DrawNormalTab")]
		private static bool DrawNormalTabPrefix(LobbyViewSettingsPane __instance)
		{
			__instance.DrawBetterNormalTab();
			return false;
		}
	}
	[HarmonyPatch(typeof(LogicGameFlowNormal))]
	internal static class LogicGameFlowNormalPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("CheckEndCriteria")]
		[HarmonyPatch("IsGameOverDueToDeath")]
		private static bool ShouldCheckForEndGame()
		{
			return !LocalConditions.ShouldDisableGameEndRequirement();
		}
	}
	[HarmonyPatch(typeof(LogicOptionsNormal))]
	internal static class LogicOptionsNormalPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("GetAnonymousVotes")]
		private static void GetAnonymousVotesPostfix(ref bool __result)
		{
			if (__result && LocalConditions.ShouldRevealVoteColors())
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(MapBehaviour))]
	internal static class MapBehaviourPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("FixedUpdate")]
		private static void FixedUpdatePostfix(MapBehaviour __instance)
		{
			__instance.BetterFixedUpdate();
		}

		[HarmonyPrefix]
		[HarmonyPatch("Show")]
		private static void ShowPrefix(MapBehaviour __instance, MapOptions opts)
		{
			__instance.BetterShow(opts);
		}
	}
	[HarmonyPatch(typeof(MapRoom))]
	internal static class MapRoomPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix(MapRoom __instance)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)__instance.special))
			{
				Vector3 localPosition = ((Component)__instance.special).transform.localPosition;
				localPosition.z = -3f;
				((Component)__instance.special).transform.localPosition = localPosition;
			}
			if (Object.op_Implicit((Object)(object)__instance.door))
			{
				Vector3 localPosition2 = ((Component)__instance.door).transform.localPosition;
				localPosition2.z = -3f;
				((Component)__instance.door).transform.localPosition = localPosition2;
			}
		}
	}
	[HarmonyPatch(typeof(MeetingHud))]
	internal static class MeetingHudPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("CastVote")]
		private static void CastVotePostfix(MeetingHud __instance, byte srcPlayerId, byte suspectPlayerId)
		{
			__instance.BetterCastVote(srcPlayerId, suspectPlayerId);
		}

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		private static void UpdatePostfix(MeetingHud __instance)
		{
			__instance.BetterUpdate();
		}

		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix(MeetingHud __instance)
		{
			__instance.BetterStart();
		}
	}
	[HarmonyPatch(typeof(NetworkedPlayerInfo))]
	internal static class NetworkedPlayerInfoPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("Deserialize")]
		private static void DeserializePostfix(NetworkedPlayerInfo __instance)
		{
			__instance.RegisterFriendCode();
		}
	}
	[HarmonyPatch(typeof(NumberOption))]
	internal static class NumberOptionPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("Initialize")]
		private static bool InitializePrefix(NumberOption __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0017: Invalid comparison between Unknown and I4
			if ((int)((OptionBehaviour)__instance).Title == 0 && (int)__instance.floatOptionName == 0)
			{
				return (int)__instance.intOptionName > 0;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch("UpdateValue")]
		private static bool UpdateValuePrefix(NumberOption __instance)
		{
			return ((OptionBehaviour)(object)__instance).CustomUpdateValue();
		}

		[HarmonyPrefix]
		[HarmonyPatch("Increase")]
		private static bool IncreasePrefix(NumberOption __instance)
		{
			__instance.BetterIncrease();
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch("Decrease")]
		private static bool DecreasePrefix(NumberOption __instance)
		{
			__instance.BetterDecrease();
			return false;
		}
	}
	[HarmonyPatch(typeof(PassiveButtonManager))]
	internal static class PassiveButtonManagerPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("Update")]
		private static bool UpdatePrefix()
		{
			return !PassiveButtonsBlocker.ShouldBlock();
		}
	}
	[HarmonyPatch(typeof(PlayerControl))]
	internal static class PlayerControlPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("HandleRpc")]
		private static void HandleRpcPostfix(PlayerControl __instance, byte callId, MessageReader reader)
		{
			if (callId == 252)
			{
				__instance.HandleCustomRpc(reader);
			}
			else
			{
				BetterVanillaManager.Instance.Cheaters.HandleRpc(__instance, callId, reader);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Awake")]
		private static void AwakePostfix(PlayerControl __instance)
		{
			if (!__instance.notRealPlayer)
			{
				GameEventManager.TriggerPlayerJoined(__instance);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("Start")]
		private static bool StartPrefix(PlayerControl __instance)
		{
			MonoBehaviourExtensions.StartCoroutine((MonoBehaviour)(object)__instance, __instance.CoBetterStart());
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch("StartMeeting")]
		private static void StartMeetingPostfix(PlayerControl __instance)
		{
			GameEventManager.TriggerMeetingStarted();
		}
	}
	[HarmonyPatch(typeof(PlayerPurchasesData))]
	internal static class PlayerPurchasesDataPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("GetPurchase")]
		private static void GetPurchasePostfix(ref bool __result)
		{
			if (LocalConditions.ShouldUnlockModdedCosmetics())
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerVoteArea))]
	internal static class PlayerVoteAreaPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix(PlayerVoteArea __instance)
		{
			((Component)__instance).gameObject.AddComponent<BetterPlayerVoteArea>();
		}
	}
	[HarmonyPatch(typeof(ProgressionScreen))]
	internal static class ProgressionScreenPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(_DoAnimations_d__14), "MoveNext")]
		private static bool _DoAnimations_d__14MoveNextPrefix(_DoAnimations_d__14 __instance)
		{
			ProgressionScreen _4__this = __instance.__4__this;
			MonoBehaviourExtensions.StartCoroutine((MonoBehaviour)(object)_4__this, _4__this.CoDoAnimations(__instance.xpGainedResult));
			return false;
		}
	}
	[HarmonyPatch(typeof(ReactorSystemType))]
	internal static class ReactorSystemTypePatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("UpdateSystem")]
		private static bool UpdateSystemPrefix(ReactorSystemType __instance, PlayerControl player, MessageReader msgReader)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			byte b = msgReader.ReadByte();
			int num = b & 3;
			if (b == 128 && !__instance.IsActive)
			{
				__instance.Countdown = (((int)ShipStatus.Instance.Type != 2) ? __instance.ReactorDuration : BetterVanillaManager.Instance.HostOptions.PolusReactorCountdown.GetFloat());
				__instance.UserConsolePairs.Clear();
			}
			else if (b == 16)
			{
				__instance.Countdown = 10000f;
			}
			else if (Extensions.HasAnyBit(b, (byte)64))
			{
				__instance.UserConsolePairs.Add(new Tuple<byte, byte>(player.PlayerId, (byte)num));
				if (__instance.UserCount >= 2)
				{
					__instance.Countdown = 10000f;
				}
			}
			else if (Extensions.HasAnyBit(b, (byte)32))
			{
				__instance.UserConsolePairs.Remove(new Tuple<byte, byte>(player.PlayerId, (byte)num));
			}
			__instance.IsDirty = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(RoleManager))]
	internal static class RoleManagerPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("SelectRoles")]
		private static bool SelectRolesPrefix(RoleManager __instance)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			if ((int)GameOptionsManager.Instance.currentGameMode != 1)
			{
				return true;
			}
			BetterVanillaManager instance = BetterVanillaManager.Instance;
			if (instance.HostOptions.AllowTeamPreference.GetBool())
			{
				instance.AllTeamPreferences[((InnerNetObject)PlayerControl.LocalPlayer).OwnerId] = instance.LocalOptions.TeamPreference.ParseValue(TeamPreferences.Both);
			}
			if (LocalConditions.IsForcedTeamAssignmentAllowed())
			{
				instance.AllForcedTeamAssignments[((InnerNetObject)PlayerControl.LocalPlayer).OwnerId] = instance.LocalOptions.ForcedTeamAssignment.ParseValue(TeamPreferences.Both);
			}
			BetterRoleAssignments betterRoleAssignments = new BetterRoleAssignments();
			betterRoleAssignments.SetTeamPreferences(instance.AllTeamPreferences);
			betterRoleAssignments.SetForcedAssignments(instance.AllForcedTeamAssignments);
			betterRoleAssignments.StartAssignation();
			return false;
		}
	}
	[HarmonyPatch(typeof(ShipStatus))]
	internal static class ShipStatusPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void StartPostfix(ShipStatus __instance)
		{
			GameEventManager.TriggerGameStarted();
		}

		[HarmonyPrefix]
		[HarmonyPatch("OnDestroy")]
		private static void OnDestroyPrefix(ShipStatus __instance)
		{
			GameEventManager.TriggerGameEnded();
		}
	}
	[HarmonyPatch(typeof(ToggleOption))]
	internal static class ToggleOptionPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("Initialize")]
		private static bool InitializePrefix(ToggleOption __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			if ((int)((OptionBehaviour)__instance).Title != 0)
			{
				return (int)__instance.boolOptionName > 0;
			}
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch("UpdateValue")]
		private static bool UpdateValuePrefix(ToggleOption __instance)
		{
			return ((OptionBehaviour)(object)__instance).CustomUpdateValue();
		}
	}
}
namespace BetterVanilla.Core.Options
{
	public abstract class BaseCategory
	{
		public readonly string Name;

		protected BaseCategory(string name)
		{
			Name = name;
			base..ctor();
		}
	}
	public abstract class BaseHostOption : BaseOption
	{
		public static readonly List<BaseHostOption> AllOptions = new List<BaseHostOption>();

		public BaseGameSetting GameSetting { get; private set; }

		public OptionBehaviour Behaviour { get; private set; }

		public ViewSettingsInfoPanel ViewBehaviour { get; private set; }

		protected BaseHostOption(string name, string title)
			: base(name, title)
		{
			AllOptions.Add(this);
		}

		public virtual float GetFloat()
		{
			throw new NotImplementedException();
		}

		public virtual int GetInt()
		{
			throw new NotImplementedException();
		}

		public virtual bool GetBool()
		{
			throw new NotImplementedException();
		}

		protected TGameSetting InitGameSetting<TGameSetting>(OptionTypes optionType) where TGameSetting : BaseGameSetting
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			TGameSetting val = ScriptableObject.CreateInstance<TGameSetting>();
			((Object)(object)val).hideFlags = (HideFlags)52;
			((Object)(object)val).name = "BetterVanillaCustomSetting";
			((BaseGameSetting)val).Title = (StringNames)0;
			((BaseGameSetting)val).Type = optionType;
			GameSetting = (BaseGameSetting)(object)val;
			return val;
		}

		public virtual void OnBehaviourCreated(OptionBehaviour behaviour)
		{
			Behaviour = behaviour;
		}

		public virtual void OnViewBehaviourCreated(ViewSettingsInfoPanel viewBehaviour)
		{
			ViewBehaviour = viewBehaviour;
		}

		protected virtual void OnValueChanged()
		{
			if (Object.op_Implicit((Object)(object)AmongUsClient.Instance) && ((InnerNetClient)AmongUsClient.Instance).AmHost && Object.op_Implicit((Object)(object)PlayerControl.LocalPlayer))
			{
				PlayerControl.LocalPlayer.RpcShareHostOption(this);
			}
			UpdateBehaviourValue();
		}

		public abstract void UpdateValueFromBehaviour();

		protected abstract void UpdateBehaviourValue();
	}
	public abstract class BaseLocalOption : BaseOption
	{
		public static readonly List<BaseLocalOption> AllOptions = new List<BaseLocalOption>();

		private string _lockHash;

		public BaseSettingBehaviour Behaviour { get; private set; }

		public event Action ValueChanged;

		protected BaseLocalOption(string name, string title)
			: base(name, title)
		{
			AllOptions.Add(this);
		}

		public virtual void OnBehaviourCreated(BaseSettingBehaviour behaviour)
		{
			Behaviour = behaviour;
		}

		public void LockWithPassword(string hash)
		{
			BetterVanillaManager.Instance.Features.RegisterHash(hash);
			_lockHash = hash;
		}

		public bool IsLocked()
		{
			if (!string.IsNullOrEmpty(_lockHash))
			{
				return BetterVanillaManager.Instance.Features.IsLocked(_lockHash);
			}
			return false;
		}

		protected virtual void OnValueChanged()
		{
			Behaviour?.UpdateFromOption();
			this.ValueChanged?.Invoke();
		}
	}
	public abstract class BaseOption
	{
		public readonly string Name;

		public string Title { get; protected set; }

		protected BaseOption(string name, string title)
		{
			Name = name;
			Title = title;
		}

		public void WriteIn(MessageWriter writer)
		{
			writer.Write(Name);
			WriteValue(writer);
		}

		public abstract void WriteValue(MessageWriter messageWriter);

		public abstract void ReadValue(MessageReader messageReader);

		public abstract string GetValueString();

		protected bool LoadValueFromDatabase(bool defaultValue)
		{
			return BetterVanillaManager.Instance.Database.Data.CurrentPreset.GetValueOrDefault(Name, defaultValue);
		}

		protected string LoadValueFromDatabase(string defaultValue)
		{
			return BetterVanillaManager.Instance.Database.Data.CurrentPreset.GetValueOrDefault(Name, defaultValue);
		}

		protected int LoadValueFromDatabase(int defaultValue)
		{
			return BetterVanillaManager.Instance.Database.Data.CurrentPreset.GetValueOrDefault(Name, defaultValue);
		}

		protected float LoadValueFromDatabase(float defaultValue)
		{
			return BetterVanillaManager.Instance.Database.Data.CurrentPreset.GetValueOrDefault(Name, defaultValue);
		}

		protected TEnum LoadValueFromDatabase<TEnum>(TEnum defaultValue) where TEnum : struct
		{
			return BetterVanillaManager.Instance.Database.Data.CurrentPreset.GetValueOrDefault(Name, defaultValue);
		}

		protected void SaveValueInDatabase(bool value)
		{
			BetterVanillaManager.Instance.Database.Data.CurrentPreset.BoolStore[Name] = value;
			BetterVanillaManager.Instance.Database.Save();
		}

		protected void SaveValueInDatabase(string value)
		{
			BetterVanillaManager.Instance.Database.Data.CurrentPreset.StringStore[Name] = value;
			BetterVanillaManager.Instance.Database.Save();
		}

		protected void SaveValueInDatabase(int value)
		{
			BetterVanillaManager.Instance.Database.Data.CurrentPreset.IntStore[Name] = value;
			BetterVanillaManager.Instance.Database.Save();
		}

		protected void SaveValueInDatabase(float value)
		{
			BetterVanillaManager.Instance.Database.Data.CurrentPreset.FloatStore[Name] = value;
			BetterVanillaManager.Instance.Database.Save();
		}

		protected void SaveValueInDatabase<TEnum>(TEnum value) where TEnum : struct
		{
			BetterVanillaManager.Instance.Database.Data.CurrentPreset.StringStore[Name] = value.ToString();
			BetterVanillaManager.Instance.Database.Save();
		}
	}
	public class BoolHostOption : BaseHostOption
	{
		private bool _value;

		private bool Value
		{
			get
			{
				return _value;
			}
			set
			{
				if (value != _value)
				{
					_value = value;
					OnValueChanged();
				}
			}
		}

		public BoolHostOption(string name, string title, bool defaultValue)
			: base(name, title)
		{
			InitGameSetting<CheckboxGameSetting>((OptionTypes)1).OptionName = (BoolOptionNames)0;
			_value = LoadValueFromDatabase(defaultValue);
		}

		public override bool GetBool()
		{
			return Value;
		}

		public override void OnBehaviourCreated(OptionBehaviour behaviour)
		{
			base.OnBehaviourCreated(behaviour);
			OptionBehaviour obj = ((behaviour is ToggleOption) ? behaviour : null) ?? throw new ArgumentException("behaviour must be ToggleOption", "behaviour");
			((TMP_Text)((ToggleOption)obj).TitleText).SetText(base.Title, true);
			((Renderer)((ToggleOption)obj).CheckMark).enabled = Value;
		}

		public override void UpdateValueFromBehaviour()
		{
			Value = base.Behaviour.GetBool();
		}

		protected override void UpdateBehaviourValue()
		{
			if (Object.op_Implicit((Object)(object)base.Behaviour))
			{
				ToggleOption obj = ((Il2CppObjectBase)base.Behaviour).TryCast<ToggleOption>();
				if (!Object.op_Implicit((Object)(object)obj))
				{
					throw new ArgumentException("behaviour must be ToggleOption");
				}
				((Renderer)obj.CheckMark).enabled = Value;
			}
			if (Object.op_Implicit((Object)(object)base.ViewBehaviour))
			{
				base.ViewBehaviour.CustomSetInfoCheckbox(61, this);
			}
		}

		public override void WriteValue(MessageWriter messageWriter)
		{
			messageWriter.Write(Value);
		}

		public override void ReadValue(MessageReader messageReader)
		{
			Value = messageReader.ReadBoolean();
		}

		public override string GetValueString()
		{
			return DestroyableSingleton<TranslationController>.Instance.GetString((StringNames)(Value ? 111 : 112), (Il2CppReferenceArray<Object>)null);
		}

		protected override void OnValueChanged()
		{
			base.OnValueChanged();
			SaveValueInDatabase(Value);
		}
	}
	public sealed class BoolLocalOption : BaseLocalOption
	{
		private bool _value;

		public bool Value
		{
			get
			{
				return _value;
			}
			set
			{
				if (value != _value)
				{
					_value = value;
					OnValueChanged();
				}
			}
		}

		public BoolLocalOption(string name, string title, bool defaultValue)
			: base(name, title)
		{
			_value = LoadValueFromDatabase(defaultValue);
		}

		public override void WriteValue(MessageWriter messageWriter)
		{
			messageWriter.Write(Value);
		}

		public override void ReadValue(MessageReader messageReader)
		{
			Value = messageReader.ReadBoolean();
		}

		public override string GetValueString()
		{
			return DestroyableSingleton<TranslationController>.Instance.GetString((StringNames)(Value ? 111 : 112), (Il2CppReferenceArray<Object>)null);
		}

		protected override void OnValueChanged()
		{
			base.OnValueChanged();
			SaveValueInDatabase(Value);
		}
	}
	public class FloatHostOption : BaseHostOption
	{
		private float _value;

		private readonly FloatGameSetting _settings;

		private float Value
		{
			get
			{
				return _value;
			}
			set
			{
				if (!Mathf.Approximately(value, _value))
				{
					_value = value;
					OnValueChanged();
				}
			}
		}

		public FloatHostOption(string name, string title, float defaultValue, float increment, FloatRange validRange, string formatString, bool zeroIsInfinity, NumberSuffixes suffixType)
			: base(name, title)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			_settings = InitGameSetting<FloatGameSetting>((OptionTypes)4);
			_settings.Value = (_value = LoadValueFromDatabase(defaultValue));
			_settings.OptionName = (FloatOptionNames)0;
			_settings.Increment = increment;
			_settings.ValidRange = validRange;
			_settings.FormatString = formatString;
			_settings.ZeroIsInfinity = zeroIsInfinity;
			_settings.SuffixType = suffixType;
		}

		public override float GetFloat()
		{
			return Value;
		}

		public override void OnBehaviourCreated(OptionBehaviour behaviour)
		{
			base.OnBehaviourCreated(behaviour);
			OptionBehaviour obj = ((behaviour is NumberOption) ? behaviour : null) ?? throw new ArgumentException("behaviour must be NumberOption", "behaviour");
			((TMP_Text)((NumberOption)obj).TitleText).SetText(base.Title, true);
			((NumberOption)obj).Value = Value;
			((NumberOption)obj).AdjustButtonsActiveState();
		}

		public override void UpdateValueFromBehaviour()
		{
			Value = base.Behaviour.GetFloat();
		}

		protected override void UpdateBehaviourValue()
		{
			if (Object.op_Implicit((Object)(object)base.Behaviour))
			{
				NumberOption obj = ((Il2CppObjectBase)base.Behaviour).TryCast<NumberOption>();
				if (!Object.op_Implicit((Object)(object)obj))
				{
					throw new ArgumentException("behaviour must be NumberOption");
				}
				obj.Value = Value;
				obj.AdjustButtonsActiveState();
			}
			if (Object.op_Implicit((Object)(object)base.ViewBehaviour))
			{
				base.ViewBehaviour?.CustomSetInfo(61, this);
			}
		}

		public override void WriteValue(MessageWriter messageWriter)
		{
			messageWriter.Write(Value);
		}

		public override void ReadValue(MessageReader messageReader)
		{
			Value = messageReader.ReadSingle();
		}

		public override string GetValueString()
		{
			return base.GameSetting.GetValueString(Value);
		}

		protected override void OnValueChanged()
		{
			base.OnValueChanged();
			SaveValueInDatabase(Value);
		}
	}
	public sealed class FloatLocalOption : BaseLocalOption
	{
		private float _value;

		public readonly float Increment;

		public readonly FloatRange ValidRange;

		public readonly string Prefix;

		public readonly string Suffix;

		public float Value
		{
			get
			{
				return _value;
			}
			set
			{
				float num = value;
				if (num > ValidRange.max)
				{
					num = ValidRange.max;
				}
				else if (num < ValidRange.min)
				{
					num = ValidRange.min;
				}
				if (!Mathf.Approximately(num, _value))
				{
					_value = num;
					OnValueChanged();
				}
			}
		}

		public FloatLocalOption(string name, string title, float defaultValue, float increment, FloatRange validRange, string prefix, string suffix)
			: base(name, title)
		{
			Increment = increment;
			ValidRange = validRange;
			Prefix = prefix;
			Suffix = suffix;
			_value = LoadValueFromDatabase(defaultValue);
		}

		public override void WriteValue(MessageWriter messageWriter)
		{
			messageWriter.Write(Value);
		}

		public override void ReadValue(MessageReader messageReader)
		{
			Value = messageReader.ReadSingle();
		}

		public override string GetValueString()
		{
			return $"{Prefix}{Value}{Suffix}";
		}

		protected override void OnValueChanged()
		{
			base.OnValueChanged();
			SaveValueInDatabase(Value);
		}
	}
	public sealed class HostCategory : BaseCategory
	{
		public static readonly List<HostCategory> AllCategories = new List<HostCategory>();

		public readonly RulesCategory GameOptionsMenuCategory;

		public readonly List<BaseHostOption> AllOptions = new List<BaseHostOption>();

		public HostCategory(string name)
			: base(name)
		{
			//IL_0013: 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)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			GameOptionsMenuCategory = new RulesCategory
			{
				CategoryName = (StringNames)0,
				AllGameSettings = new List<BaseGameSetting>()
			};
			AllCategories.Add(this);
		}

		private void RegisterInCategory(BaseHostOption option)
		{
			AllOptions.Add(option);
			GameOptionsMenuCategory.AllGameSettings.Add(option.GameSetting);
		}

		public BoolHostOption CreateBool(string name, string title, bool defaultValue)
		{
			BoolHostOption boolHostOption = new BoolHostOption(name, title, defaultValue);
			RegisterInCategory(boolHostOption);
			return boolHostOption;
		}

		public IntHostOption CreateInt(string name, string title, int defaultValue, int increment, IntRange validRange, string formatString, bool zeroIsInfinity, NumberSuffixes suffixType)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			IntHostOption intHostOption = new IntHostOption(name, title, defaultValue, increment, validRange, formatString, zeroIsInfinity, suffixType);
			RegisterInCategory(intHostOption);
			return intHostOption;
		}

		public FloatHostOption CreateFloat(string name, string title, float defaultValue, float increment, FloatRange validRange, string formatString, bool zeroIsInfinity, NumberSuffixes suffixType)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			FloatHostOption floatHostOption = new FloatHostOption(name, title, defaultValue, increment, validRange, formatString, zeroIsInfinity, suffixType);
			RegisterInCategory(floatHostOption);
			return floatHostOption;
		}
	}
	public class IntHostOption : BaseHostOption
	{
		private int _value;

		private int Value
		{
			get
			{
				return _value;
			}
			set
			{
				if (value != _value)
				{
					_value = value;
					OnValueChanged();
				}
			}
		}

		public IntHostOption(string name, string title, int defaultValue, int increment, IntRange validRange, string formatString, bool zeroIsInfinity, NumberSuffixes suffixType)
			: base(name, title)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			IntGameSetting obj = InitGameSetting<IntGameSetting>((OptionTypes)5);
			obj.Value = (_value = LoadValueFromDatabase(defaultValue));
			obj.OptionName = (Int32OptionNames)0;
			obj.Increment = increment;
			obj.ValidRange = validRange;
			obj.FormatString = formatString;
			obj.ZeroIsInfinity = zeroIsInfinity;
			obj.SuffixType = suffixType;
		}

		public override int GetInt()
		{
			return Value;
		}

		public override void OnBehaviourCreated(OptionBehaviour behaviour)
		{
			base.OnBehaviourCreated(behaviour);
			OptionBehaviour obj = ((behaviour is NumberOption) ? behaviour : null) ?? throw new ArgumentException("behaviour must be NumberOption", "behaviour");
			((TMP_Text)((NumberOption)obj).TitleText).SetText(base.Title, true);
			((NumberOption)obj).Value = Value;
			((NumberOption)obj).AdjustButtonsActiveState();
		}

		public override void UpdateValueFromBehaviour()
		{
			Value = base.Behaviour.GetInt();
		}

		protected override void UpdateBehaviourValue()
		{
			if (Object.op_Implicit((Object)(object)base.Behaviour))
			{
				NumberOption obj = ((Il2CppObjectBase)base.Behaviour).TryCast<NumberOption>();
				if (!Object.op_Implicit((Object)(object)obj))
				{
					throw new ArgumentException("behaviour must be NumberOption");
				}
				obj.Value = Value;
				obj.AdjustButtonsActiveState();
			}
			if (Object.op_Implicit((Object)(object)base.ViewBehaviour))
			{
				base.ViewBehaviour?.CustomSetInfo(61, this);
			}
		}

		public override void WriteValue(MessageWriter messageWriter)
		{
			messageWriter.Write(Value);
		}

		public override void ReadValue(MessageReader messageReader)
		{
			Value = messageReader.ReadInt32();
		}

		public override string GetValueString()
		{
			return base.GameSetting.GetValueString((float)Value);
		}

		protected override void OnValueChanged()
		{
			base.OnValueChanged();
			SaveValueInDatabase(Value);
		}
	}
	public sealed class IntLocalOption : BaseLocalOption
	{
		private int _value;

		public readonly int Increment;

		public readonly IntRange ValidRange;

		public readonly string Prefix;

		public readonly string Suffix;

		public int Value
		{
			get
			{
				return _value;
			}
			set
			{
				int num = value;
				if (num > ValidRange.max)
				{
					num = ValidRange.max;
				}
				else if (num < ValidRange.min)
				{
					num = ValidRange.min;
				}
				if (!Mathf.Approximately((float)num, (float)_value))
				{
					_value = num;
					OnValueChanged();
				}
			}
		}

		public IntLocalOption(string name, string title, int defaultValue, int increment, IntRange validRange, string prefix, string suffix)
			: base(name, title)
		{
			Increment = increment;
			ValidRange = validRange;
			Prefix = prefix;
			Suffix = suffix;
			_value = LoadValueFromDatabase(defaultValue);
		}

		public override void WriteValue(MessageWriter messageWriter)
		{
			messageWriter.Write(Value);
		}

		public override void ReadValue(MessageReader messageReader)
		{
			Value = messageReader.ReadInt32();
		}

		public override string GetValueString()
		{
			return $"{Prefix}{Value}{Suffix}";
		}

		protected override void OnValueChanged()
		{
			base.OnValueChanged();
			SaveValueInDatabase(Value);
		}
	}
	public sealed class LocalCategory : BaseCategory
	{
		public static readonly List<LocalCategory> AllCategories = new List<LocalCategory>();

		public readonly List<BaseLocalOption> AllOptions = new List<BaseLocalOption>();

		public LocalCategory(string name)
			: base(name)
		{
			AllCategories.Add(this);
		}

		private void RegisterInCategory(BaseLocalOption option)
		{
			AllOptions.Add(option);
		}

		public BoolLocalOption CreateBool(string name, string title, bool defaultValue)
		{
			BoolLocalOption boolLocalOption = new BoolLocalOption(name, title, defaultValue);
			RegisterInCategory(boolLocalOption);
			return boolLocalOption;
		}

		public IntLocalOption CreateInt(string name, string title, int defaultValue, int increment, IntRange validRange, string prefix = "", string suffix = "")
		{
			IntLocalOption intLocalOption = new IntLocalOption(name, title, defaultValue, increment, validRange, prefix, suffix);
			RegisterInCategory(intLocalOption);
			return intLocalOption;
		}

		public FloatLocalOption CreateFloat(string name, string title, float defaultValue, float increment, FloatRange validRange, string prefix = "", string suffix = "")
		{
			FloatLocalOption floatLocalOption = new FloatLocalOption(name, title, defaultValue, increment, validRange, prefix, suffix);
			RegisterInCategory(floatLocalOption);
			return floatLocalOption;
		}

		public StringLocalOption CreateEnum<TEnum>(string name, string title, TEnum defaultValue) where TEnum : struct
		{
			Type typeFromHandle = typeof(TEnum);
			if (!typeFromHandle.IsEnum)
			{
				throw new ArgumentException("Type must be an enum", typeFromHandle.FullName);
			}
			Array values = Enum.GetValues(typeFromHandle);
			List<string> list = new List<string>();
			List<string> list2 = new List<string>();
			string text = defaultValue.ToString();
			foreach (TEnum item in values)
			{
				string text2 = item.ToString();
				if (text2 == null)
				{
					throw new Exception($"Unable to stringify enum key {item} in {typeFromHandle.FullName}");
				}
				FieldInfo? field = typeFromHandle.GetField(text2);
				if (field == null)
				{
					throw new Exception("Unable to find field " + text2 + " in " + typeFromHandle.FullName);
				}
				NamedFieldAttribute customAttribute = field.GetCustomAttribute<NamedFieldAttribute>();
				string text3 = ((customAttribute == null) ? text2 : customAttribute.Name);
				list.Add(text3);
				list2.Add(text2);
				if (text2 == text)
				{
					text = text3;
				}
			}
			StringLocalOption stringLocalOption = new StringLocalOption(name, title, text, list, list2);
			RegisterInCategory(stringLocalOption);
			return stringLocalOption;
		}
	}
	public class StringLocalOption : BaseLocalOption
	{
		private int _index;

		private readonly List<string> _realValues;

		public readonly List<string> Values;

		public int Index
		{
			get
			{
				return _index;
			}
			set
			{
				if (value != _index && value >= 0 && value < Values.Count)
				{
					_index = value;
					OnValueChanged();
				}
			}
		}

		public string Value => Values[_index];

		public string RealValue => _realValues[_index];

		private int FindIndex(string value)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			int num = Values.IndexOf(value);
			if (num < 0 || num >= Values.Count)
			{
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(38, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Unable to find '");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' in Values in ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("StringLocalOption");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" named ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(Name);
				}
				Ls.LogWarning(val);
				num = 0;
			}
			return num;
		}

		public StringLocalOption(string name, string title, string defaultValue, List<string> values, List<string> realValues)
			: base(name, title)
		{
			_realValues = realValues;
			Values = values;
			_index = LoadValueFromDatabase(FindIndex(defaultValue));
		}

		public override void WriteValue(MessageWriter messageWriter)
		{
			messageWriter.Write(Index);
		}

		public override void ReadValue(MessageReader messageReader)
		{
			Index = messageReader.ReadInt32();
		}

		public override string GetValueString()
		{
			return Value;
		}

		public TEnum ParseValue<TEnum>(TEnum defaultValue) where TEnum : struct
		{
			Type typeFromHandle = typeof(TEnum);
			if (!typeFromHandle.IsEnum)
			{
				throw new ArgumentException("Type myst be enum", typeFromHandle.Name);
			}
			if (!Enum.TryParse<TEnum>(RealValue, out var result))
			{
				return defaultValue;
			}
			return result;
		}

		protected override void OnValueChanged()
		{
			base.OnValueChanged();
			SaveValueInDatabase(Index);
		}
	}
}
namespace BetterVanilla.Core.Helpers
{
	public static class AssetBundleUtils
	{
		public static AssetBundle LoadFromExecutingAssembly(string assetBundleName)
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			return AssetBundle.LoadFromMemory(Il2CppStructArray<byte>.op_Implicit(StreamExtensions.ReadBytes(executingAssembly.GetManifestResourceStream(assetBundleName) ?? throw new Exception("Unable to find resource: " + assetBundleName + " in assembly " + executingAssembly.FullName))));
		}
	}
	public static class ColorUtils
	{
		public static readonly Color CheaterColor = Palette.ImpostorRed;

		public static readonly Color HostColor = Color.magenta;

		public static readonly Color ImpostorColor = Palette.ImpostorRed;

		private static readonly Color NoTasksDoneColor = new Color(0.76f, 0.16f, 0.52f, 1f);

		private static readonly Color AllTasksDoneColor = new Color(0.34f, 1f, 0.69f, 1f);

		public static Color TaskCountColor(int done, int total)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			float num = (float)done / (float)total;
			return Color.Lerp(NoTasksDoneColor, AllTasksDoneColor, num);
		}

		private static byte ToByte(float f)
		{
			f = Mathf.Clamp01(f);
			return (byte)(f * 255f);
		}

		public static string ColoredString(Color c, string s)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			return $"<color=#{ToByte(c.r):X2}{ToByte(c.g):X2}{ToByte(c.b):X2}{ToByte(c.a):X2}>{s}</color>";
		}

		public static string ToHex(Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			int value = Mathf.RoundToInt(color.r * 255f);
			int value2 = Mathf.RoundToInt(color.g * 255f);
			int value3 = Mathf.RoundToInt(color.b * 255f);
			int value4 = Mathf.RoundToInt(color.a * 255f);
			return $"#{value:X2}{value2:X2}{value3:X2}{value4:X2}";
		}

		public static Color FromHex(string hexColor)
		{
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			if (hexColor.StartsWith("#"))
			{
				hexColor = hexColor.Replace("#", string.Empty);
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			int num4 = 255;
			switch (hexColor.Length)
			{
			case 8:
				num = int.Parse(MemoryExtensions.AsSpan(hexColor, 0, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
				num2 = int.Parse(MemoryExtensions.AsSpan(hexColor, 2, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
				num3 = int.Parse(MemoryExtensions.AsSpan(hexColor, 4, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
				num4 = int.Parse(MemoryExtensions.AsSpan(hexColor, 6, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
				break;
			case 6:
				num = int.Parse(MemoryExtensions.AsSpan(hexColor, 0, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
				num2 = int.Parse(MemoryExtensions.AsSpan(hexColor, 2, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
				num3 = int.Parse(MemoryExtensions.AsSpan(hexColor, 4, 2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
				break;
			case 3:
				num = int.Parse(hexColor[0].ToString() + hexColor[0], NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
				num2 = int.Parse(hexColor[1].ToString() + hexColor[1], NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
				num3 = int.Parse(hexColor[2].ToString() + hexColor[2], NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
				break;
			}
			return new Color((float)num / 255f, (float)num2 / 255f, (float)num3 / 255f, (float)num4 / 255f);
		}
	}
	public static class CoroutineUtils
	{
		public static IEnumerator CoAssertWithTimeout(Func<bool> assertion, Action onTimeout, float timeoutInSeconds)
		{
			bool failed = true;
			for (float timer = 0f; timer < timeoutInSeconds; timer += Time.deltaTime)
			{
				if (assertion())
				{
					failed = false;
					break;
				}
				yield return null;
			}
			if (failed)
			{
				onTimeout?.Invoke();
			}
		}

		public static IEnumerator RandomWait(float min = 1f, float max = 10f)
		{
			float num = Random.RandomRange(1f, 10f);
			yield return (object)new WaitForSeconds(num);
		}
	}
	public static class StringUtils
	{
		public static string CalculateSHA256(string text)
		{
			byte[] bytes = Encoding.UTF8.GetBytes(text);
			using SHA256 sHA = SHA256.Create();
			return BitConverter.ToString(sHA.ComputeHash(bytes)).Replace("-", "");
		}
	}
}
namespace BetterVanilla.Core.Extensions
{
	public static class AssetBundleExtensions
	{
		public static T LoadAsset<T>(this AssetBundle assetBundle, string name) where T : Object
		{
			return ((Il2CppObjectBase)assetBundle.LoadAsset(name, Il2CppType.Of<T>())).Cast<T>();
		}

		public static T LoadComponent<T>(this AssetBundle assetBundle, string name) where T : MonoBehaviour
		{
			return assetBundle.LoadAsset<GameObject>(name).GetComponent<T>();
		}
	}
	public static class CategoryHeaderMaskedExtensions
	{
		private static readonly int StencilComp = Shader.PropertyToID("_StencilComp");

		private static readonly int Stencil = Shader.PropertyToID("_Stencil");

		public static void CustomSetHeader(this CategoryHeaderMasked headerMasked, int maskLayer, HostCategory category)
		{
			((TMP_Text)headerMasked.Title).SetText(category.Name, true);
			((Renderer)headerMasked.Background).material.SetInt(PlayerMaterial.MaskLayer, maskLayer);
			if (Object.op_Implicit((Object)(object)headerMasked.Divider))
			{
				((Renderer)headerMasked.Divider).material.SetInt(PlayerMaterial.MaskLayer, maskLayer);
			}
			((TMP_Text)headerMasked.Title).fontMaterial.SetFloat(StencilComp, 3f);
			((TMP_Text)headerMasked.Title).fontMaterial.SetFloat(Stencil, (float)maskLayer);
		}
	}
	public static class ChatBubbleExtensions
	{
		public static void SetPrivateChatBubbleName(this ChatBubble bubble, NetworkedPlayerInfo senderInfo, NetworkedPlayerInfo receiverInfo, bool isDead, bool didVote, Color nameColor)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			string text = ((PlayerControl.LocalPlayer.Data.PlayerName == receiverInfo.PlayerName) ? "me" : receiverInfo.PlayerName);
			string text2 = senderInfo.PlayerName + " " + ColorUtils.ColoredString(Color.gray, "[to " + text + "]");
			bubble.SetName(text2, isDead, didVote, nameColor);
		}
	}
	public static class ChatControllerExtensions
	{
		public static void AddPrivateChat(this ChatController controller, PlayerControl sender, PlayerControl receiver, string chatText)
		{
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)sender) || !Object.op_Implicit((Object)(object)receiver))
			{
				return;
			}
			NetworkedPlayerInfo data = sender.Data;
			NetworkedPlayerInfo data2 = receiver.Data;
			if ((Object)(object)data2 == (Object)null || (Object)(object)data == (Object)null)
			{
				return;
			}
			ChatBubble pooledBubble = controller.GetPooledBubble();
			try
			{
				Transform transform = ((Component)pooledBubble).transform;
				transform.SetParent(controller.scroller.Inner);
				transform.localScale = Vector3.one;
				bool num = (Object)(object)sender == (Object)(object)PlayerControl.LocalPlayer;
				if (num)
				{
					pooledBubble.SetRight();
				}
				else
				{
					pooledBubble.SetLeft();
				}
				bool didVote = Object.op_Implicit((Object)(object)MeetingHud.Instance) && MeetingHud.Instance.DidVote(sender.PlayerId);
				pooledBubble.SetCosmetics(data);
				int colorId = data.Outfits[(PlayerOutfitType)0].ColorId;
				ChatBubbleExtensions.SetPrivateChatBubbleName(nameColor: Color32.op_Implicit((colorId < ((Il2CppArrayBase<Color32>)(object)Palette.PlayerColors).Count) ? ((Il2CppArrayBase<Color32>)(object)Palette.PlayerColors)[colorId] : ((Il2CppArrayBase<Color32>)(object)Palette.PlayerColors)[0]), bubble: pooledBubble, senderInfo: data, receiverInfo: data2, isDead: data.IsDead, didVote: didVote);
				pooledBubble.SetText(chatText);
				pooledBubble.AlignChildren();
				controller.AlignAllBubbles();
				if (!controller.IsOpenOrOpening && controller.notificationRoutine == null)
				{
					controller.notificationRoutine = ((MonoBehaviour)controller).StartCoroutine(controller.BounceDot());
				}
				if (!num)
				{
					SoundManager.Instance.PlaySound(controller.messageSound, false, 1f, (AudioMixerGroup)null).pitch = (float)(0.5 + (double)(int)sender.PlayerId / 15.0);
				}
			}
			catch (Exception ex)
			{
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(45, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("ChatControllerPatches.AddPrivateChat: failed ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				Ls.LogWarning(val);
				((IObjectPool)controller.chatBubblePool).Reclaim((PoolableBehavior)(object)pooledBubble);
			}
		}
	}
	public static class EndGameNavigationExtensions
	{
		public static void SetupPlayAgain(this EndGameNavigation navigation)
		{
			if (LocalConditions.ShouldAutoPlayAgain())
			{
				MonoBehaviourExtensions.StartCoroutine((MonoBehaviour)(object)navigation, navigation.CoPlayAgain());
			}
		}

		private static IEnumerator CoPlayAgain(this EndGameNavigation navigation)
		{
			while (!navigation.ContinueButton.activeSelf)
			{
				yield return (object)new WaitForEndOfFrame();
			}
			yield return (object)new WaitForSeconds(3f);
			PassiveButton componentInChildren = navigation.ContinueButton.GetComponentInChildren<PassiveButton>();
			if (Object.op_Implicit((Object)(object)componentInChildren) && ((Behaviour)componentInChildren).enabled)
			{
				((UnityEvent)componentInChildren.OnClick).Invoke();
			}
			while (!((Renderer)navigation.PlayAgainButton).enabled)
			{
				yield return (object)new WaitForEndOfFrame();
			}
			yield return (object)new WaitForSeconds(3f);
			PassiveButton component = ((Component)navigation.PlayAgainButton).gameObject.GetComponent<PassiveButton>();
			if (Object.op_Implicit((Object)(object)component) && ((Behaviour)component).enabled)
			{
				((UnityEvent)component.OnClick).Invoke();
			}
		}
	}
	public static class EnumerableExtensions
	{
		public static List<T> ToIl2CppList<T>(this IEnumerable<T> enumerable)
		{
			List<T> val = new List<T>();
			foreach (T item in enumerable)
			{
				val.Add(item);
			}
			return val;
		}
	}
	public static class GameManagerExtensions
	{
		public static List<RulesCategory> GetAllCategories(this GameManager gameManager)
		{
			List<RulesCategory> list = new List<RulesCategory>();
			foreach (HostCategory allCategory in HostCategory.AllCategories)
			{
				list.Add(allCategory.GameOptionsMenuCategory);
			}
			Enumerator<RulesCategory> enumerator2 = gameManager.GameSettingsList.AllCategories.GetEnumerator();
			while (enumerator2.MoveNext())
			{
				RulesCategory current2 = enumerator2.Current;
				list.Add(current2);
			}
			return list;
		}
	}
	public static class GameOptionsMenuExtensions
	{
		public static bool CustomValueChanged(this GameOptionsMenu menu, OptionBehaviour optionBehaviour)
		{
			BaseHostOption baseHostOption = BaseHostOption.AllOptions.Find((BaseHostOption x) => (Object)(object)x.Behaviour == (Object)(object)optionBehaviour);
			if (baseHostOption == null)
			{
				return true;
			}
			baseHostOption.UpdateValueFromBehaviour();
			return false;
		}

		public static void CreateBetterSettings(this GameOptionsMenu menu)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Expected I4, but got Unknown
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			float num = 0.713f;
			foreach (RulesCategory allCategory in GameManager.Instance.GetAllCategories())
			{
				HostCategory hostCategory = HostCategory.AllCategories.Find((HostCategory x) => ((Il2CppObjectBase)x.GameOptionsMenuCategory).Pointer == ((Il2CppObjectBase)allCategory).Pointer);
				CategoryHeaderMasked val = Object.Instantiate<CategoryHeaderMasked