Decompiled source of FusionGuard Quest v8.4.9

Mods/FusionGuard.dll

Decompiled a day ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.Notifications;
using FusionGuard;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Combat;
using Il2CppSLZ.Marrow.Data;
using Il2CppSLZ.Marrow.Interaction;
using Il2CppSLZ.Marrow.Pool;
using Il2CppSLZ.Marrow.VFX;
using Il2CppSLZ.Marrow.Warehouse;
using Il2CppSLZ.VRMK;
using Il2CppSystem.Collections.Generic;
using LabFusion.Data;
using LabFusion.Entities;
using LabFusion.Extensions;
using LabFusion.Marrow.Extenders;
using LabFusion.Marrow.Messages;
using LabFusion.Marrow.Serialization;
using LabFusion.Network;
using LabFusion.Player;
using LabFusion.Preferences;
using LabFusion.Preferences.Server;
using LabFusion.Representation;
using LabFusion.SDK.Gamemodes;
using LabFusion.SDK.Metadata;
using LabFusion.Senders;
using LabFusion.Utilities;
using LabFusion.Voice;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.VFX;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Core), "FusionGuard Quest", "8.4.9", "DragonBird", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonAdditionalDependencies(new string[] { "LabFusion" })]
[assembly: AssemblyMetadata("AIGenerated", "Code written with the help of Claude (Anthropic)")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 FusionGuard
{
	internal class PendingSpawn
	{
		public object Handler;

		public MethodInfo Method;

		public ReceivedMessage Message;

		public byte Owner;

		public int EntityID = -1;

		public bool Particle;
	}
	internal class FxEntry
	{
		public Poolee Poolee;

		public GameObject Go;

		public byte Owner;

		public float Time;
	}
	internal static class FusionCompat
	{
		private const BindingFlags PubStatic = BindingFlags.Static | BindingFlags.Public;

		private const BindingFlags PubInst = BindingFlags.Instance | BindingFlags.Public;

		private static PropertyInfo _playerIdPlat;

		private static PropertyInfo _playerInfoPlat;

		private static MethodInfo _fetchPerm;

		private static MethodInfo _setPerm;

		private static MethodInfo _pardon;

		private static bool _init;

		private static MethodInfo _deny;

		private static MethodInfo _disconnectUser;

		internal static bool StringIds { get; private set; }

		internal static string Mode => StringIds ? "Fusion EOS (Epic/Quest)" : "Official Fusion (SteamVR)";

		internal static bool PermsOk
		{
			get
			{
				Init();
				return _fetchPerm != null;
			}
		}

		internal static void Init()
		{
			if (!_init)
			{
				_init = true;
				_playerIdPlat = typeof(PlayerID).GetProperty("PlatformID", BindingFlags.Instance | BindingFlags.Public);
				_playerInfoPlat = typeof(PlayerInfo).GetProperty("PlatformID", BindingFlags.Instance | BindingFlags.Public);
				StringIds = _playerIdPlat != null && _playerIdPlat.PropertyType == typeof(string);
				Type typeFromHandle = typeof(FusionPermissions);
				_fetchPerm = typeFromHandle.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "FetchPermissionLevel" && m.GetParameters().Length == 3);
				_setPerm = typeFromHandle.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "TrySetPermission" && m.GetParameters().Length == 3);
				_pardon = typeof(NetworkHelper).GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "PardonUser" && m.GetParameters().Length == 1);
			}
		}

		internal static string Plat(PlayerID player)
		{
			if (player == null)
			{
				return string.Empty;
			}
			Init();
			return Normalize(_playerIdPlat?.GetValue(player));
		}

		internal static string BanPlat(PlayerInfo info)
		{
			if (info == null)
			{
				return string.Empty;
			}
			Init();
			return Normalize(_playerInfoPlat?.GetValue(info));
		}

		internal static bool Has(string plat)
		{
			return !string.IsNullOrEmpty(plat);
		}

		private static string Normalize(object value)
		{
			if (value == null)
			{
				return string.Empty;
			}
			if (value is ulong num)
			{
				return (num == 0L) ? string.Empty : num.ToString();
			}
			return value.ToString() ?? string.Empty;
		}

		private static bool TryArg(string plat, Type target, out object arg)
		{
			arg = null;
			if (!Has(plat))
			{
				return false;
			}
			if (target == typeof(string))
			{
				arg = plat;
				return true;
			}
			if (target == typeof(ulong) && ulong.TryParse(plat, out var result))
			{
				arg = result;
				return true;
			}
			return false;
		}

		internal static PermissionLevel FetchPermission(string plat)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			Init();
			if (_fetchPerm == null || !TryArg(plat, _fetchPerm.GetParameters()[0].ParameterType, out var arg))
			{
				return (PermissionLevel)0;
			}
			object[] array = new object[3] { arg, null, null };
			_fetchPerm.Invoke(null, array);
			return (PermissionLevel)((array[1] is PermissionLevel val) ? ((int)val) : 0);
		}

		internal static void SetPermission(string plat, string username, PermissionLevel level)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			Init();
			if (!(_setPerm == null) && TryArg(plat, _setPerm.GetParameters()[0].ParameterType, out var arg))
			{
				_setPerm.Invoke(null, new object[3] { arg, username, level });
			}
		}

		internal static void Deny(string plat, string reason)
		{
			try
			{
				if (_deny == null)
				{
					_deny = typeof(ConnectionSender).GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "SendConnectionDeny" && m.GetParameters().Length == 2);
				}
				if (!(_deny == null) && TryArg(plat, _deny.GetParameters()[0].ParameterType, out var arg))
				{
					_deny.Invoke(null, new object[2] { arg, reason });
				}
			}
			catch
			{
			}
		}

		internal static void Pardon(string plat)
		{
			Init();
			if (!(_pardon == null) && TryArg(plat, _pardon.GetParameters()[0].ParameterType, out var arg))
			{
				_pardon.Invoke(null, new object[1] { arg });
			}
		}

		internal static void CloseConnection(string plat)
		{
			try
			{
				if (_disconnectUser == null)
				{
					_disconnectUser = typeof(NetworkConnectionManager).GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "DisconnectUser" && m.GetParameters().Length == 1);
				}
				if (!(_disconnectUser == null) && TryArg(plat, _disconnectUser.GetParameters()[0].ParameterType, out var arg))
				{
					_disconnectUser.Invoke(null, new object[1] { arg });
				}
			}
			catch
			{
			}
		}
	}
	internal static class PlatformDetect
	{
		private const BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static bool _init;

		private static bool _ok;

		private static PropertyInfo _connectProp;

		private static FieldInfo _runtimeField;

		private static FieldInfo _connIface;

		private static FieldInfo _localUser;

		private static MethodInfo _fromString;

		private static MethodInfo _copyInfo;

		private static MethodInfo _query;

		private static ConstructorInfo _utfCtor;

		private static Type _copyOptT;

		private static Type _queryOptT;

		private static Type _puidT;

		private static Delegate _callback;

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

		private static readonly Dictionary<string, float> asked = new Dictionary<string, float>();

		private static void Init()
		{
			if (_init)
			{
				return;
			}
			_init = true;
			try
			{
				Assembly assembly = typeof(PlayerID).Assembly;
				Type type = assembly.GetType("LabFusion.Network.EOSRuntime");
				Type type2 = assembly.GetType("LabFusion.Network.EpicGamesNetworkLayer");
				if (type2 != null)
				{
					_runtimeField = type2.GetField("Runtime", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				}
				Type type3 = assembly.GetType("LabFusion.Network.EOSConnect");
				_puidT = assembly.GetType("Epic.OnlineServices.ProductUserId");
				Type type4 = assembly.GetType("Epic.OnlineServices.Utf8String");
				Type type5 = assembly.GetType("Epic.OnlineServices.Connect.ConnectInterface");
				_copyOptT = assembly.GetType("Epic.OnlineServices.Connect.CopyProductUserInfoOptions");
				_queryOptT = assembly.GetType("Epic.OnlineServices.Connect.QueryProductUserIdMappingsOptions");
				Type type6 = assembly.GetType("Epic.OnlineServices.Connect.OnQueryProductUserIdMappingsCallback");
				if (!(type == null) && !(type3 == null) && !(_puidT == null) && !(type4 == null) && !(type5 == null) && !(_copyOptT == null) && !(_queryOptT == null) && !(type6 == null))
				{
					_connectProp = type.GetProperty("Connect", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					_connIface = type3.GetField("ConnectInterface", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					_localUser = type3.GetField("LocalUserId", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					_fromString = _puidT.GetMethod("FromString", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { type4 }, null);
					_utfCtor = type4.GetConstructor(new Type[1] { typeof(string) });
					_copyInfo = type5.GetMethod("CopyProductUserInfo", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					_query = type5.GetMethod("QueryProductUserIdMappings", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					Type parameterType = type6.GetMethod("Invoke").GetParameters()[0].ParameterType;
					ParameterExpression parameterExpression = Expression.Parameter(parameterType, "data");
					_callback = Expression.Lambda(type6, Expression.Empty(), parameterExpression).Compile();
					_ok = _connectProp != null && _runtimeField != null && _connIface != null && _localUser != null && _fromString != null && _utfCtor != null && _copyInfo != null && _query != null;
				}
			}
			catch (Exception ex)
			{
				_ok = false;
				MelonLogger.Warning("[Platform] init : " + ex.Message);
			}
		}

		internal static void Clear()
		{
			asked.Clear();
		}

		internal static string Get(string plat)
		{
			if (!FusionCompat.Has(plat))
			{
				return "?";
			}
			if (!FusionCompat.StringIds)
			{
				return "PC";
			}
			if (cache.TryGetValue(plat, out var value))
			{
				return value;
			}
			Init();
			if (!_ok)
			{
				return "?";
			}
			try
			{
				object layer = NetworkLayerManager.Layer;
				if (layer == null || !_runtimeField.DeclaringType.IsInstanceOfType(layer))
				{
					return "?";
				}
				object value2 = _runtimeField.GetValue(layer);
				object obj = ((value2 != null) ? _connectProp.GetValue(value2) : null);
				if (obj == null)
				{
					return "?";
				}
				object value3 = _connIface.GetValue(obj);
				object value4 = _localUser.GetValue(obj);
				object obj2 = _fromString.Invoke(null, new object[1] { _utfCtor.Invoke(new object[1] { plat }) });
				if (value3 == null || obj2 == null)
				{
					return "?";
				}
				object obj3 = Activator.CreateInstance(_copyOptT);
				_copyOptT.GetProperty("TargetUserId").SetValue(obj3, obj2);
				object[] array = new object[2] { obj3, null };
				object obj4 = _copyInfo.Invoke(value3, array);
				if (obj4 != null && obj4.ToString() == "Success" && array[1] != null)
				{
					object obj5 = array[1];
					string text = obj5.GetType().GetProperty("AccountIdType")?.GetValue(obj5)?.ToString() ?? "";
					string text2 = text switch
					{
						"Epic" => "PC (Epic)", 
						"Oculus" => "QUEST", 
						"Steam" => "PC", 
						_ => text.ToUpperInvariant(), 
					};
					if (!string.IsNullOrEmpty(text2))
					{
						cache[plat] = text2;
						return text2;
					}
				}
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (value4 != null && (!asked.TryGetValue(plat, out var value5) || realtimeSinceStartup - value5 > 20f))
				{
					asked[plat] = realtimeSinceStartup;
					object obj6 = Activator.CreateInstance(_queryOptT);
					_queryOptT.GetProperty("LocalUserId").SetValue(obj6, value4);
					Array array2 = Array.CreateInstance(_puidT, 1);
					array2.SetValue(obj2, 0);
					_queryOptT.GetProperty("ProductUserIds").SetValue(obj6, array2);
					_query.Invoke(value3, new object[3] { obj6, null, _callback });
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[Platform] " + (ex.InnerException?.Message ?? ex.Message));
			}
			return "?";
		}
	}
	internal class SecAlert
	{
		public string Kind;

		public byte Small;

		public string PlatformID;

		public string Name;

		public string Reason;

		public int Count;

		public float Last;

		public byte? Target;

		public string TargetName;

		public bool Ban;

		public bool Kicked;

		public float KickedAt;

		public bool Allowed;
	}
	internal class PlayerHold
	{
		public byte SmallID;

		public string PlatformID;

		public string Name;

		public int Total;

		public int Particles;

		public int Dropped;

		public bool ByParticles;

		public bool Quarantine;

		public int ScoreAtStart;

		public readonly Dictionary<string, int> Counts = new Dictionary<string, int>();

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

		public readonly List<PendingSpawn> Queue = new List<PendingSpawn>();

		public readonly List<PendingSpawn> FxQueue = new List<PendingSpawn>();
	}
	public class Core : MelonMod
	{
		private delegate void PlatSetter(ref ReadableMessage message, string plat);

		private class GuardBan
		{
			public string Plat;

			public string Name;

			public string Reason;

			public string Date;
		}

		private class GodTrack
		{
			public float Start = -1f;

			public int Hits;

			public float MinRatio = 1f;

			public float LastH;

			public float LastM;

			public float LastDrop = -1f;

			public readonly List<float> RegenHits = new List<float>();

			public int BadHealth;

			public int AvatarId;
		}

		private class MsgCounter
		{
			public float Since;

			public int Count;

			public int Over;

			public long Bytes;

			public int OverBytes;
		}

		private sealed class LobbyPlayerRow
		{
			public string Name;

			public string User;

			public string Id;

			public string Fg;

			public string Watch;

			public bool HasFg;
		}

		private sealed class LobbyRow
		{
			public string Key;

			public string Name;

			public string Host;

			public string Code;

			public string Level;

			public string Mode;

			public string Privacy;

			public string FgHostVer;

			public string FgHostPlat;

			public int Count;

			public int Max;

			public int FgCount;

			public bool FgHost;

			public bool Open;

			public List<LobbyPlayerRow> Players = new List<LobbyPlayerRow>();

			public Action Join;
		}

		private struct RecentSpawn
		{
			public ushort Id;

			public byte Owner;

			public float Time;
		}

		private class NetStat
		{
			public int Msgs;

			public int Spawns;

			public int Despawns;

			public int Owners;

			public int Damage;

			public int Kicks;

			public long Bytes;

			public readonly Dictionary<string, int> Types = new Dictionary<string, int>();
		}

		private class GunTrack
		{
			public int LastAmmo = -1;

			public float LastShot;

			public int NoDrop;

			public readonly Queue<float> Times = new Queue<float>();

			public Gun Gun;

			public float GunAt;

			public readonly List<KeyValuePair<float, Vector3>> Aim = new List<KeyValuePair<float, Vector3>>();
		}

		private class LastShotInfo
		{
			public float Time;

			public ushort GunId;

			public Gun Gun;
		}

		private class RecentShot
		{
			public float Time;

			public Vector3 Muzzle;

			public Vector3 Forward;

			public float Spread;

			public float TurnSpeed;
		}

		private class GrabOnMe
		{
			public byte Sender;

			public Handedness Hand;

			public float Since;

			public float BadSince = -1f;
		}

		private class DmgSample
		{
			public byte Shooter;

			public float K;

			public string Gun;
		}

		private class FreezeState
		{
			public Vector3 Pos;

			public float LastTp;

			public string Name;
		}

		private class AimEval
		{
			public float Time;

			public bool Sus;

			public float Angle;
		}

		private class AimShot
		{
			public float Time;

			public byte Target = byte.MaxValue;

			public float Dist;

			public bool Snap;

			public float Peak;

			public bool Hit;

			public bool Head;

			public bool Moving;
		}

		private class BlockedWord
		{
			public string Word;

			public bool On = true;

			public bool Everywhere;
		}

		private class ApprovalHold
		{
			public byte SmallID;

			public string PlatformID;

			public string Name;

			public float Since;

			public readonly List<PendingSpawn> Queue = new List<PendingSpawn>();

			public readonly Dictionary<string, int> Counts = new Dictionary<string, int>();
		}

		private enum ItemKind
		{
			Toggle,
			Slider,
			Cycle,
			Page,
			Action,
			Info,
			Header
		}

		private class MenuItem
		{
			public string Label;

			public ItemKind Kind;

			public Func<bool> GetBool;

			public Action<bool> SetBool;

			public Func<float> GetFloat;

			public Action<float> SetFloat;

			public float Min;

			public float Max;

			public float Step;

			public string Suffix = "";

			public Func<string> GetText;

			public Action Click;

			public MenuPage Target;

			public bool HasTint;

			public Color Tint;

			public string Key;

			public string ConfirmKey;
		}

		private class MenuPage
		{
			public string Title;

			public MenuPage Parent;

			public int Scroll;

			public bool NoSave;

			public object Tag;

			public Func<int> Badge;

			public string Desc;

			public List<MenuItem> Items = new List<MenuItem>();
		}

		private class UiButton
		{
			public Renderer Rend;

			public Vector2 Center;

			public Vector2 Half;

			public Color Base;

			public Action Press;

			public string Key;
		}

		private class TpBack
		{
			public Vector3 Pos;

			public Vector3 SentTo;

			public string Plat;
		}

		private class StateSlot
		{
			public MenuItem It;

			public MelonPreferences_Entry<bool> B;

			public MelonPreferences_Entry<float> F;

			public MelonPreferences_Entry<string> S;
		}

		internal static Core Instance;

		private static int _isQuest = -1;

		internal static bool Replaying;

		private static MethodInfo handleMethod;

		private static MethodInfo requestMethod;

		private bool protection = true;

		private bool antiSpawn = false;

		private bool allowPerms = true;

		private int preset = 1;

		private float threshold = 15f;

		private float window = 3f;

		private float loadSpeed = 4f;

		private float maxQueue = 1500f;

		private bool trustHost = true;

		private bool autoOpen = true;

		private bool autoClose = true;

		private bool notifications = true;

		private bool hostFilter = true;

		private bool clientFilter = true;

		private bool warnHold = true;

		private bool warnBlocked = true;

		private bool logAll = false;

		private bool blockItems = true;

		private bool askExplosives = true;

		private bool fxFilter = true;

		private float fxThreshold = 10f;

		private float fxWindow = 3f;

		private float maxActiveFx = 40f;

		private bool blockAllFx = false;

		private bool limitSpawnFx = true;

		private float spawnFxPerSec = 10f;

		private bool antiCheatDamage = true;

		private bool autoKick = true;

		private float kickStrikes = 3f;

		private float meleeRange = 3f;

		private bool antiKickServer = true;

		private bool antiFakeKick = true;

		private bool kickNotifs = true;

		private bool secPopup = true;

		private bool godDetect = true;

		private bool confirmOpKicks = false;

		private bool antiFakePerms = true;

		private bool antiHijack = true;

		private bool antiForeignDespawn = true;

		private bool limitAvatarSpam = true;

		private bool antiHealthHack = true;

		private float godHits = 10f;

		private bool antiBadPose = true;

		private bool antiFlood = true;

		private float floodLimit = 3000f;

		private float floodKB = 512f;

		private bool antiGamemodeTriggers = true;

		private bool antiFakeTp = true;

		private bool limitTeleports = true;

		private int triggersBlocked;

		private int tpBlocked;

		private int ghostDropped;

		private bool operatorMode = true;

		private bool autoBanCrashSpam = true;

		private bool hostCrashDespawn = true;

		private bool kickNukeSpam = true;

		private float nukeKickAt = 2f;

		private float explosiveKickAt = 6f;

		private int spawnKicks;

		private float crashSpamSecs = 5f;

		private bool shieldMode = false;

		private int shieldDropped;

		private int autoBans;

		private bool antiGodGuns = true;

		private bool antiSilentAim = true;

		private bool detectAimLock = true;

		private bool antiInfiniteAmmo = true;

		private bool antiWallbang = true;

		private bool antiNoShotDamage = true;

		private bool antiRemoteGrab = true;

		private bool antiFling = true;

		private float flingSpeed = 60f;

		private int combatBlocked;

		private int grabsBlocked;

		private int flingsStopped;

		private int ammoAlerts;

		private bool warnBannedJoin = true;

		private bool watchScanLobbies = true;

		private bool detectDmgMult = true;

		private bool antiKillAir = true;

		private int multAlerts;

		private int godScanHits;

		private const int MaxMessageBytes = 262144;

		private const int MaxMetadataChars = 1024;

		private bool antiRemoteFire = true;

		private bool antiSlowMo = true;

		private bool antiLinks = true;

		private float avatarMax = 6f;

		private static readonly string[] PresetNames = new string[5] { "Low", "Normal", "High", "Max", "Custom" };

		private static readonly string[] SpawnPermNames = new string[3] { "Normal", "Trusted", "Blocked" };

		private static readonly string[] PermNames = new string[4] { "Guest", "Default", "Operator", "Owner" };

		private static readonly float[] PresetThreshold = new float[4] { 40f, 15f, 8f, 4f };

		private static readonly float[] PresetWindow = new float[4] { 3f, 3f, 3f, 2f };

		private bool applyingPreset = false;

		private const int BindCount = 5;

		private int menuBind = 1;

		private int menuHand = 0;

		private int menuAccent = 0;

		private float menuSize = 1f;

		private float textSize = 1f;

		private bool haptics = true;

		private int touchSafety = 0;

		private static readonly string[] TouchNames = new string[2] { "Normal", "Strict" };

		private MelonPreferences_Entry<bool> tutorialPref;

		private GameObject hintRoot;

		private TextMesh hintLine2;

		private string hintBind;

		private readonly List<Material> hintMats = new List<Material>();

		private bool hintNotified;

		private const string TsNamespace = "FusionGuardTeam";

		private bool checkUpdates = true;

		private volatile bool updBusy;

		private bool updAvailable;

		private bool updNotifyPending;

		private string updLatest;

		private string updStatus = "Not checked yet";

		private MenuPage updPage;

		private static readonly string[] AccentNames = new string[6] { "Cyan", "Purple", "Green", "Orange", "Pink", "Rainbow" };

		private static readonly Color[] AccentColors = (Color[])(object)new Color[5]
		{
			new Color(0.2f, 0.85f, 1f, 1f),
			new Color(0.66f, 0.45f, 1f, 1f),
			new Color(0.25f, 0.9f, 0.5f, 1f),
			new Color(1f, 0.6f, 0.2f, 1f),
			new Color(1f, 0.4f, 0.75f, 1f)
		};

		private float aimHeadshots = 5f;

		private float aimDistance = 15f;

		private float silentShots = 4f;

		private float fireRateMargin = 50f;

		private float killAirPct = 50f;

		private float graceUntil;

		private const float GraceSeconds = 12f;

		private readonly Dictionary<byte, Queue<float>> recent = new Dictionary<byte, Queue<float>>();

		private readonly Dictionary<byte, PlayerHold> holds = new Dictionary<byte, PlayerHold>();

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

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

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

		private readonly Dictionary<byte, Queue<float>> recentFx = new Dictionary<byte, Queue<float>>();

		private readonly Dictionary<byte, Queue<float>> recentAmmo = new Dictionary<byte, Queue<float>>();

		private int fxDropped;

		private readonly Dictionary<string, bool> fxCache = new Dictionary<string, bool>();

		private readonly Dictionary<string, bool> fxGuess = new Dictionary<string, bool>();

		private readonly Dictionary<int, FxEntry> activeFx = new Dictionary<int, FxEntry>();

		private readonly Queue<float> spawnFxTimes = new Queue<float>();

		private int fxCapped;

		private readonly List<SecAlert> alerts = new List<SecAlert>();

		private readonly Dictionary<byte, float> lastHeld = new Dictionary<byte, float>();

		private readonly Dictionary<byte, List<float>> strikes = new Dictionary<byte, List<float>>();

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

		private readonly Dictionary<string, float> lastSecNotify = new Dictionary<string, float>();

		private int dmgBlocked;

		private int kicksBlocked;

		private float heldTimer;

		private SecAlert autoOpenAlert;

		private readonly Dictionary<byte, GodTrack> godTrack = new Dictionary<byte, GodTrack>();

		private readonly Dictionary<byte, Queue<float>> dmgRate = new Dictionary<byte, Queue<float>>();

		private float godTimer;

		private float permTimer;

		private readonly Dictionary<byte, float> poseQuarantine = new Dictionary<byte, float>();

		private readonly Dictionary<byte, float> downUntil = new Dictionary<byte, float>();

		private readonly Dictionary<byte, List<float>> badPoseStrikes = new Dictionary<byte, List<float>>();

		private readonly Dictionary<byte, List<float>> bigMsgStrikes = new Dictionary<byte, List<float>>();

		private readonly Dictionary<byte, List<float>> gunStrikes = new Dictionary<byte, List<float>>();

		private readonly Dictionary<byte, List<float>> slowMoStrikes = new Dictionary<byte, List<float>>();

		private readonly Dictionary<byte, MsgCounter> msgCount = new Dictionary<byte, MsgCounter>();

		private readonly Dictionary<string, int> cheatScore = new Dictionary<string, int>();

		private int badPoses;

		private int floodDropped;

		private int remoteFireBlocked;

		private readonly Dictionary<byte, List<float>> hijackStrikes = new Dictionary<byte, List<float>>();

		private readonly Dictionary<byte, List<float>> despawnStrikes = new Dictionary<byte, List<float>>();

		private readonly Dictionary<byte, Queue<float>> avatarSwaps = new Dictionary<byte, Queue<float>>();

		private int netBlocked;

		private int foreignDespawns;

		private readonly Dictionary<byte, float> lastDeath = new Dictionary<byte, float>();

		private readonly Dictionary<byte, float> godFlagged = new Dictionary<byte, float>();

		private readonly Dictionary<byte, float> hpFlagged = new Dictionary<byte, float>();

		private int godAlerts;

		private const float HoldGrace = 6f;

		private int spawnFxSkipped;

		private float fxTimer;

		private static readonly string[] GunFxWords = new string[7] { "muzzle", "tracer", "tracers", "casing", "casings", "shellcasing", "brass" };

		private static readonly string[] FxWords = new string[19]
		{
			"vfx", "fx", "particle", "particles", "smoke", "explosion", "explosions", "spark", "sparks", "effect",
			"effects", "firework", "fireworks", "confetti", "fog", "nuke", "blood", "splash", "flash"
		};

		private readonly Queue<PendingSpawn> replayQueue = new Queue<PendingSpawn>();

		private int blockedDropped;

		private bool holdsDirty;

		private float holdsRefreshTimer;

		private bool menuAutoOpened;

		private bool pendingAutoOpen;

		private PlayerHold autoOpenTarget;

		private readonly Dictionary<byte, List<ushort>> spawnedBy = new Dictionary<byte, List<ushort>>();

		private readonly Dictionary<byte, int> spawnCount = new Dictionary<byte, int>();

		private readonly List<string> spawnLog = new List<string>();

		private readonly Dictionary<byte, float> lastWarn = new Dictionary<byte, float>();

		private bool adminDirty = true;

		private float adminTimer;

		private string boneAdminSig = "";

		private readonly List<GameObject> hiddenProps = new List<GameObject>();

		private string confirmKey;

		private float confirmUntil;

		private string lastActiveScene;

		private static FieldInfo _discPlatF;

		private static FieldInfo _discReasonF;

		[ThreadStatic]
		private static string _eosPeer;

		[ThreadStatic]
		private static bool _eosFresh;

		[ThreadStatic]
		private static bool _eosNetDisconnect;

		[ThreadStatic]
		private static bool _eosServerHandled;

		[ThreadStatic]
		private static bool _eosNativeCheck;

		private static bool eosPatched;

		private static bool eosNativeOn;

		private bool antiSpoof = true;

		private int spoofBlocked;

		private readonly Dictionary<string, List<float>> spoofStrikes = new Dictionary<string, List<float>>();

		private static FieldInfo _backupIdField;

		private readonly Dictionary<string, float> blockedPeers = new Dictionary<string, float>();

		private readonly Dictionary<string, float> joinGrace = new Dictionary<string, float>();

		private readonly Dictionary<string, float> peerCloseAt = new Dictionary<string, float>();

		private readonly Dictionary<string, float> ghostLogAt = new Dictionary<string, float>();

		private readonly Dictionary<string, int> ghostCount = new Dictionary<string, int>();

		private static bool eosIdsMatch;

		private static FieldInfo _rcvP2P;

		private static FieldInfo _p2pPool;

		private static MethodInfo _poolReturn;

		private static bool _poolInit;

		private static FieldInfo _p2pLocalId;

		private static long _selfPackets;

		private static bool _selfLogged;

		private static PlatSetter _setPlat;

		private bool lockdown = false;

		private bool quarantineOn = true;

		private float quarantineSecs = 45f;

		private bool autoSanctions = true;

		private float sanctionBlockAt = 2f;

		private float sanctionKickAt = 3f;

		private float sanctionBanAt = 5f;

		private bool antiRejoin = true;

		private bool epicAccountCheck = true;

		private bool securityLogFile = true;

		private bool strongHaptics = true;

		private readonly Dictionary<byte, float> firstSeen = new Dictionary<byte, float>();

		private float serverSeenAt = -1f;

		private readonly Dictionary<string, List<float>> kickHistory = new Dictionary<string, List<float>>();

		private readonly Dictionary<string, float> tempBans = new Dictionary<string, float>();

		private readonly Dictionary<string, List<float>> joinAttempts = new Dictionary<string, List<float>>();

		private readonly Dictionary<string, int> sanctionDone = new Dictionary<string, int>();

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

		private readonly Dictionary<string, float> banKickAt = new Dictionary<string, float>();

		private readonly Dictionary<string, int> voiceMute = new Dictionary<string, int>();

		private int joinsDenied;

		private bool hapticPending;

		private float lastDenyNotify;

		private static readonly HashSet<string> SevereKinds = new HashSet<string> { "kickcheat", "spoof", "badpose", "flood", "hijack", "fakekick", "fakeperm", "remotefire", "damage", "faketp" };

		private static readonly HashSet<string> ScoreKinds = new HashSet<string> { "kickcheat", "spoof", "fakekick", "fakeperm", "flood", "badpose", "remotefire", "nukespam" };

		private readonly Dictionary<string, GuardBan> guardBans = new Dictionary<string, GuardBan>();

		private string trustedSig = "";

		private readonly Dictionary<byte, string> slotOwner = new Dictionary<byte, string>();

		private static PropertyInfo _recvPlatProp;

		private bool muteAllNonStaff;

		private readonly Dictionary<byte, KeyValuePair<float, bool>> staffCache = new Dictionary<byte, KeyValuePair<float, bool>>();

		private readonly Dictionary<string, float> lastNetCheat = new Dictionary<string, float>();

		private readonly Dictionary<byte, float> cullSeen = new Dictionary<byte, float>();

		private const float CullGrace = 3f;

		private readonly Dictionary<byte, float> disarmAt = new Dictionary<byte, float>();

		private static bool shotWatchPatched;

		private int disarms;

		private const float PoseLimit = 100000f;

		private static FieldInfo _bodiesField;

		private static PropertyInfo _bodiesProp;

		private static bool _bodiesInit;

		private static FieldInfo _gunIdF;

		private static FieldInfo _gunF;

		private static FieldInfo _entF;

		private static FieldInfo _idF;

		private static bool _gunInit;

		private const string GuardKey = "FusionGuard";

		private float guardTimer;

		private int guardTries;

		private readonly HashSet<byte> guardSeen = new HashSet<byte>();

		internal const bool AdminBuild = false;

		private const string LobbyGuardKey = "FusionGuard";

		private bool shareLobbyFg = true;

		private bool lobbyFgPatched;

		private string lobbyFgSig;

		private float nextLobbyFgWrite;

		private readonly List<LobbyRow> lobbyRows = new List<LobbyRow>();

		private MenuPage lobbyPage;

		private bool lobbyBusy;

		private float lobbyReqAt;

		private float lobbyLoadedAt = -1f;

		private string lobbyStatus = "Open this page to load the lobby list";

		private const string MegaKey = "FusionGuard.Mega";

		private bool megaphone;

		private readonly Dictionary<byte, KeyValuePair<float, bool>> megaCache = new Dictionary<byte, KeyValuePair<float, bool>>();

		private readonly HashSet<int> megaApplied = new HashSet<int>();

		private static readonly Vector3 VanishSpot = new Vector3(0f, -4000f, 0f);

		private bool vanish;

		private bool vanishPatched;

		private readonly Dictionary<string, List<float>> crashSeconds = new Dictionary<string, List<float>>();

		private readonly Dictionary<string, float> crashKickAt = new Dictionary<string, float>();

		private readonly Dictionary<string, List<float>> nukeTries = new Dictionary<string, List<float>>();

		private readonly Dictionary<string, List<float>> explosiveTries = new Dictionary<string, List<float>>();

		private readonly Dictionary<string, float> spawnKickAt = new Dictionary<string, float>();

		private readonly Dictionary<byte, float> shieldDrop = new Dictionary<byte, float>();

		private readonly List<RecentSpawn> recentSpawns = new List<RecentSpawn>();

		private bool netDebug = true;

		private float netSummarySecs = 10f;

		private readonly Dictionary<byte, NetStat> netStats = new Dictionary<byte, NetStat>();

		private readonly Dictionary<byte, string> netRoster = new Dictionary<byte, string>();

		private readonly Dictionary<string, float> netLineAt = new Dictionary<string, float>();

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

		private float netSummaryTimer;

		private float netStatusTimer;

		private float netRosterTimer;

		[ThreadStatic]
		private static bool _fgDropped;

		private const byte NetNoSender = byte.MaxValue;

		private static readonly FieldInfo _discPlatF2 = typeof(DisconnectMessageData).GetField("PlatformID", BindingFlags.Instance | BindingFlags.Public);

		private static readonly FieldInfo _discReasonF2 = typeof(DisconnectMessageData).GetField("Reason", BindingFlags.Instance | BindingFlags.Public);

		private readonly Dictionary<byte, List<RecentShot>> recentShots = new Dictionary<byte, List<RecentShot>>();

		private readonly Dictionary<ushort, GunTrack> gunTracks = new Dictionary<ushort, GunTrack>();

		private readonly Dictionary<byte, LastShotInfo> lastShotBy = new Dictionary<byte, LastShotInfo>();

		private readonly HashSet<byte> infAmmoPopped = new HashSet<byte>();

		private readonly Dictionary<string, float> combatNotifyAt = new Dictionary<string, float>();

		private readonly Dictionary<string, List<float>> combatStrikes = new Dictionary<string, List<float>>();

		[ThreadStatic]
		private static bool _dmgCertain;

		private static FieldInfo _ammoF;

		private static bool _ammoInit;

		private static FieldInfo _gunIdxF;

		private static FieldInfo _gunIdxInner;

		private static bool _gunIdxInit;

		private static FieldInfo _magGunF;

		private static FieldInfo _magEjGunF;

		private static readonly Dictionary<int, bool> solidLayerCache = new Dictionary<int, bool>();

		private static readonly string[] SoftLayerWords = new string[18]
		{
			"ignore", "nocollide", "trigger", "player", "ui", "water", "block", "clip", "nav", "invisible",
			"socket", "deciverse", "feet", "hand", "interactable", "ragdoll", "effect", "fx"
		};

		private static readonly Handedness HandLeft = (Handedness)1;

		private readonly List<GrabOnMe> grabsOnMe = new List<GrabOnMe>();

		private float flingWatchUntil;

		private float flingNotifyAt;

		private Rigidbody[] myRbs;

		private float myRbsAt;

		private readonly Dictionary<string, float> bannedJoinAt = new Dictionary<string, float>();

		private const string DefaultWatchlist = "nyro,nyro.dll";

		private const int WatchlistVersion = 2;

		private MelonPreferences_Entry<string> watchPref;

		private MelonPreferences_Entry<int> watchVer;

		private readonly Dictionary<byte, string> watchSeen = new Dictionary<byte, string>();

		private readonly Dictionary<string, float> watchLobbyAt = new Dictionary<string, float>();

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

		private readonly List<DmgSample>[] dmgSamples = new List<DmgSample>[2]
		{
			new List<DmgSample>(),
			new List<DmgSample>()
		};

		private readonly Dictionary<byte, List<float>> shooterRatios = new Dictionary<byte, List<float>>();

		private readonly Dictionary<byte, float> multFlagged = new Dictionary<byte, float>();

		private readonly Dictionary<byte, FreezeState> frozen = new Dictionary<byte, FreezeState>();

		[ThreadStatic]
		private static bool _freezeTp;

		private readonly Dictionary<byte, List<AimEval>> aimEvals = new Dictionary<byte, List<AimEval>>();

		private int aimAlerts;

		private readonly Dictionary<byte, List<AimShot>> aimShots = new Dictionary<byte, List<AimShot>>();

		private readonly Dictionary<byte, List<KeyValuePair<float, Vector3>>> holdAim = new Dictionary<byte, List<KeyValuePair<float, Vector3>>>();

		private readonly Dictionary<byte, KeyValuePair<float, Vector3>> pelvisLast = new Dictionary<byte, KeyValuePair<float, Vector3>>();

		private readonly Dictionary<byte, float> pelvisSpeed = new Dictionary<byte, float>();

		private int aimLockAlerts;

		private readonly Dictionary<byte, List<float>> triggerTimes = new Dictionary<byte, List<float>>();

		private readonly Dictionary<byte, List<float>> triggerStrikes = new Dictionary<byte, List<float>>();

		private readonly Dictionary<byte, List<float>> tpTimes = new Dictionary<byte, List<float>>();

		private readonly Dictionary<byte, List<float>> tpStrikes = new Dictionary<byte, List<float>>();

		private readonly Dictionary<byte, List<float>> fakeTpStrikes = new Dictionary<byte, List<float>>();

		private static readonly Regex LinkRegex = new Regex("(https?://|www\\.|discord\\.gg|discord\\.com/invite|\\b[a-z0-9-]{2,}\\.(com|net|org|gg|fun|xyz|io|ru|tk|ly|me|tv|site|online|shop)\\b)", RegexOptions.IgnoreCase | RegexOptions.Compiled);

		private static bool vfxBroken;

		private static readonly string[] AmmoWords = new string[12]
		{
			"magazine", "magazines", "mag", "mags", "ammo", "clip", "clips", "shell", "shells", "cartridge",
			"battery", "cell"
		};

		private readonly Dictionary<string, bool> ammoCache = new Dictionary<string, bool>();

		private static readonly string[] DefaultBlockedItems = new string[8] { "!nuke", "missile", "explosion", "explosive", "bomb", "c4", "!void spawn", "!void orb" };

		private static readonly string[] AllowedItemWords = new string[3] { "rpg", "launcher", "bazooka" };

		private const int BlockedItemsVersion = 3;

		private readonly List<BlockedWord> blockedItems = new List<BlockedWord>();

		private MelonPreferences_Entry<string> blockedItemsPref;

		private MelonPreferences_Entry<int> blockedItemsVer;

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

		private readonly Dictionary<string, BlockedWord> itemMatch = new Dictionary<string, BlockedWord>();

		private int itemsBlocked;

		private MenuPage itemsPage;

		private static readonly string[] ExplosiveWords = new string[17]
		{
			"explosive", "explosion", "grenade", "bomb", "c4", "missile", "rocket", "nuke", "mine", "landmine",
			"dynamite", "tnt", "claymore", "detonator", "frag", "molotov", "warhead"
		};

		private readonly Dictionary<byte, ApprovalHold> approvals = new Dictionary<byte, ApprovalHold>();

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

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

		private readonly Dictionary<string, bool> explosiveCache = new Dictionary<string, bool>();

		private ApprovalHold autoOpenApproval;

		private int explosivesRefused;

		private const int MaxApprovalQueue = 30;

		private const float ApprovalTimeout = 90f;

		private static int mainThreadId = -1;

		private static readonly ConcurrentQueue<Action> mainQueue = new ConcurrentQueue<Action>();

		private float nextMenuErr;

		private bool menuOpen = false;

		private bool lastCombo = false;

		private float menuAnim = 0f;

		private GameObject menuRoot;

		private GameObject pointerBall;

		private Renderer pointerRend;

		private MenuPage homePage;

		private MenuPage currentPage;

		private MenuPage pendingPage;

		private MenuPage playersPage;

		private MenuPage filterPage;

		private MenuPage fxPage;

		private MenuPage securityPage;

		private MenuPage netPage;

		private MenuPage toolsPage;

		private MenuPage settingsPage;

		private MenuPage watchPage;

		private readonly List<UiButton> uiButtons = new List<UiButton>();

		private readonly List<Material> menuMats = new List<Material>();

		private readonly List<Renderer> accentRends = new List<Renderer>();

		private readonly List<TextMesh> accentTexts = new List<TextMesh>();

		private Animator fingerAnim;

		private float nextFingerSearch;

		private Font menuFont;

		private Material textMat;

		private bool fontSearched = false;

		private bool pressLock = false;

		private UiButton armedBtn;

		private UiButton approachBtn;

		private float armedSince;

		private float approachTime;

		private float settleUntil;

		private const int HiddenLayer = 0;

		private static readonly Color CBg = new Color(0.05f, 0.055f, 0.07f, 1f);

		private static readonly Color CTop = new Color(0.075f, 0.082f, 0.104f, 1f);

		private static readonly Color CSide = new Color(0.068f, 0.075f, 0.096f, 1f);

		private static readonly Color CCard = new Color(0.108f, 0.118f, 0.15f, 1f);

		private static readonly Color CInfo = new Color(0.08f, 0.088f, 0.112f, 1f);

		private static readonly Color CChip = new Color(0.155f, 0.168f, 0.212f, 1f);

		private static readonly Color CTrack = new Color(0.215f, 0.228f, 0.275f, 1f);

		private static readonly Color COn = new Color(0.2f, 0.8f, 0.45f, 1f);

		private static readonly Color COff = new Color(0.3f, 0.32f, 0.38f, 1f);

		private static readonly Color CText = new Color(0.95f, 0.96f, 1f, 1f);

		private static readonly Color CTextDim = new Color(0.76f, 0.79f, 0.87f, 1f);

		private static readonly Color CSub = new Color(0.55f, 0.6f, 0.7f, 1f);

		private static readonly Color CGood = new Color(0.11f, 0.42f, 0.25f, 1f);

		private static readonly Color CDanger = new Color(0.5f, 0.12f, 0.15f, 1f);

		private static readonly Color CArmed = new Color(0.9f, 0.15f, 0.12f, 1f);

		private static readonly Color CWarn = new Color(1f, 0.78f, 0.3f, 1f);

		private static readonly Color CAlert = new Color(1f, 0.45f, 0.45f, 1f);

		private static readonly Color CHeader = CTop;

		private static readonly Color CRow = CCard;

		private static readonly Color CRowSoft = CInfo;

		private static readonly Color CTile = CCard;

		private static readonly Color CNav = CChip;

		private static readonly Color TLoad = new Color(0.13f, 0.5f, 0.3f, 1f);

		private static readonly Color TTrust = new Color(0.12f, 0.36f, 0.55f, 1f);

		private static readonly Color TRefuse = new Color(0.45f, 0.1f, 0.12f, 1f);

		private static readonly Color TBlock = new Color(0.3f, 0.05f, 0.06f, 1f);

		private static readonly Color TFrozen = new Color(0.1f, 0.32f, 0.72f, 1f);

		private static readonly Color KAlerts = new Color(1f, 0.56f, 0.26f, 1f);

		private static readonly Color KPlayers = new Color(0.38f, 0.66f, 1f, 1f);

		private static readonly Color KServer = new Color(0.68f, 0.52f, 1f, 1f);

		private static readonly Color KSpawns = new Color(1f, 0.8f, 0.3f, 1f);

		private static readonly Color KParticles = new Color(1f, 0.46f, 0.76f, 1f);

		private static readonly Color KCheat = new Color(1f, 0.36f, 0.4f, 1f);

		private static readonly Color KNetwork = new Color(0.3f, 0.86f, 0.76f, 1f);

		private static readonly Color KSettings = new Color(0.66f, 0.7f, 0.78f, 1f);

		private const float PW = 0.37f;

		private const float PH = 0.36f;

		private const float MW = 0.37f;

		private const float MH = 0.36f;

		private const float SideW = 0.082f;

		private const float CL = -0.087f;

		private const float CR = 0.175f;

		private const float CW = 0.262f;

		private const float CX = 0.044f;

		private const float RW = 0.262f;

		private const float RowH = 0.031f;

		private const float RowStep = 0.038f;

		private const int RowsPerPage = 6;

		private const float HitInset = 0.002f;

		private MenuPage serverPage;

		private readonly Dictionary<byte, TpBack> tpBack = new Dictionary<byte, TpBack>();

		private MenuPage resumePage;

		private bool tutorialSessionDone;

		private float nextHintErr;

		private MenuPage lastDrawnPage;

		private bool lastArmedState;

		private Color drawCat;

		private static Shader menuShader;

		private static bool shaderSearched;

		private static readonly string[] ShaderNames = new string[5] { "Hidden/Internal-Colored", "Universal Render Pipeline/Unlit", "Unlit/Color", "Sprites/Default", "UI/Default" };

		private Page bonePending;

		private Page bonePlayers;

		private Page boneTools;

		private MelonPreferences_Category stateCat;

		private readonly List<StateSlot> stateSlots = new List<StateSlot>();

		private bool loadingState = false;

		private bool saveQueued;

		private float saveTimer;

		internal static bool IsQuest
		{
			get
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Invalid comparison between Unknown and I4
				if (_isQuest < 0)
				{
					try
					{
						_isQuest = (((int)Application.platform == 11) ? 1 : 0);
					}
					catch
					{
						_isQuest = ((Environment.OSVersion.Platform == PlatformID.Unix) ? 1 : 0);
					}
				}
				return true;
			}
		}

		internal static bool RealAndroid
		{
			get
			{
				_ = IsQuest;
				return _isQuest == 1;
			}
		}

		private static bool GuardOn => Instance != null && Instance.protection;

		private bool TutorialDone
		{
			get
			{
				try
				{
					return tutorialPref != null && tutorialPref.Value;
				}
				catch
				{
					return true;
				}
			}
		}

		private static string TsPackage => IsQuest ? "FusionGuard_Quest" : "FusionGuard";

		private string BansPath => Path.Combine(GuardDir(), "bans.txt");

		private string ImportPath => Path.Combine(GuardDir(), "import_bans.txt");

		private string TrustedPath => Path.Combine(GuardDir(), "trusted.txt");

		private bool ShieldActive => shieldMode && NetworkInfo.HasServer && !NetworkInfo.IsHost;

		private static bool OnMainThread => Thread.CurrentThread.ManagedThreadId == mainThreadId;

		private bool IsGunFx(string barcode)
		{
			string text = CrateWords(barcode);
			string[] gunFxWords = GunFxWords;
			foreach (string text2 in gunFxWords)
			{
				if (text.Contains(" " + text2 + " "))
				{
					return true;
				}
			}
			return false;
		}

		public override void OnInitializeMelon()
		{
			Instance = this;
			mainThreadId = Thread.CurrentThread.ManagedThreadId;
			bool flag = true;
			try
			{
				if (MelonBase.RegisteredMelons.Any((MelonBase m) => m != null && (object)m != this && m.Info != null && m.Info.Name == "FusionGuard Admin"))
				{
					((MelonBase)this).LoggerInstance.Error("FusionGuard Admin is also installed: this FusionGuard disables itself. Keep only one of the DLLs.");
					Instance = null;
					try
					{
						((MelonBase)this).Unregister("FusionGuard Admin already installed", false);
						return;
					}
					catch
					{
						return;
					}
				}
			}
			catch
			{
			}
			try
			{
				if (MelonBase.RegisteredMelons.Any((MelonBase m) => m != null && m.Info != null && m.Info.Name == "FusionGuard"))
				{
					((MelonBase)this).LoggerInstance.Error("FusionGuard (PC) is also installed: FusionGuard Quest disables itself. Keep only one of the two DLLs.");
					Instance = null;
					try
					{
						((MelonBase)this).Unregister("FusionGuard (PC) already installed", false);
						return;
					}
					catch
					{
						return;
					}
				}
			}
			catch
			{
			}
			FusionCompat.Init();
			if (!RealAndroid)
			{
				((MelonBase)this).LoggerInstance.Warning("This build is made for Quest standalone. On PC, use FusionGuard (PC).");
			}
			((MelonBase)this).LoggerInstance.Msg("Fusion version detected: " + FusionCompat.Mode);
			((MelonBase)this).LoggerInstance.Msg("Platform: " + (IsQuest ? "Quest standalone (Android / LemonLoader)" : "PC"));
			if (IsQuest)
			{
				maxActiveFx = 25f;
				spawnFxPerSec = 6f;
			}
			PatchFusion();
			BuildPages();
			LoadState();
			LoadTrusted();
			SetupBoneMenu();
			try
			{
				MelonPreferences_Category val = MelonPreferences.CreateCategory("FusionGuard");
				tutorialPref = val.CreateEntry<bool>("TutorialDone", false, (string)null, "true once the hand menu has been opened (hides the \"how to open\" hint)", false, false, (ValueValidator)null, (string)null);
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Warning("[Tutorial] " + ex.Message);
			}
			if (!IsQuest && checkUpdates)
			{
				CheckForUpdates(manual: false);
			}
			((MelonBase)this).LoggerInstance.Msg("FusionGuard Quest 8.4.9 loaded. Hand menu: " + BindName() + " on the " + ((menuHand == 0) ? "left" : "right") + " hand");
		}

		public override void OnSceneWasInitialized(int buildIndex, string sceneName)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			menuRoot = null;
			pointerBall = null;
			menuOpen = false;
			menuAnim = 0f;
			uiButtons.Clear();
			menuMats.Clear();
			DestroyHint();
			hintRoot = null;
			fingerAnim = null;
			armedBtn = null;
			approachBtn = null;
			lastDrawnPage = null;
			accentRends.Clear();
			accentTexts.Clear();
			graceUntil = Time.realtimeSinceStartup + 12f;
			string text = sceneName ?? "";
			try
			{
				Scene activeScene = SceneManager.GetActiveScene();
				text = ((Scene)(ref activeScene)).name ?? text;
			}
			catch
			{
			}
			if (text != lastActiveScene)
			{
				lastActiveScene = text;
				try
				{
					ClearPending();
				}
				catch (Exception ex)
				{
					((MelonBase)this).LoggerInstance.Warning("[Map] " + ex.Message);
				}
			}
		}

		public override void OnApplicationQuit()
		{
			try
			{
				SaveTrustedIfChanged();
			}
			catch
			{
			}
			SaveState();
		}

		private void PatchFusion()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Expected O, but got Unknown
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Expected O, but got Unknown
			try
			{
				handleMethod = typeof(SpawnResponseMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (handleMethod == null)
				{
					((MelonBase)this).LoggerInstance.Error("SpawnResponseMessage.OnHandleMessage not found (different Fusion version?)");
					return;
				}
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)handleMethod, new HarmonyMethod(typeof(Core).GetMethod("SpawnPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Guard] patch spawn Fusion OK");
				requestMethod = typeof(SpawnRequestMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (requestMethod != null)
				{
					((MelonBase)this).HarmonyInstance.Patch((MethodBase)requestMethod, new HarmonyMethod(typeof(Core).GetMethod("ServerSpawnPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					((MelonBase)this).LoggerInstance.Msg("[Guard] anti-spawn host OK");
				}
				else
				{
					((MelonBase)this).LoggerInstance.Warning("[Guard] SpawnRequestMessage.OnHandleMessage not found, host anti-spawn disabled");
				}
				MethodInfo method = typeof(SpawnResponseMessage).GetMethod("OnSpawnFinished", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (method != null)
				{
					((MelonBase)this).HarmonyInstance.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(Core).GetMethod("SpawnFinishedPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					((MelonBase)this).LoggerInstance.Msg("[Guard] particle tracking OK");
				}
				else
				{
					((MelonBase)this).LoggerInstance.Warning("[Guard] SpawnResponseMessage.OnSpawnFinished not found, active particle limit disabled");
				}
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Error("[Guard] Fusion patch failed: " + ex);
			}
			try
			{
				MethodInfo method2 = typeof(SpawnEffects).GetMethod("CallSpawnEffect", BindingFlags.Static | BindingFlags.Public);
				if (method2 != null)
				{
					((MelonBase)this).HarmonyInstance.Patch((MethodBase)method2, new HarmonyMethod(typeof(Core).GetMethod("SpawnEffectPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					((MelonBase)this).LoggerInstance.Msg("[Guard] spawn effect limit OK");
				}
			}
			catch (Exception ex2)
			{
				((MelonBase)this).LoggerInstance.Error("[Guard] Fusion patch failed: " + ex2);
			}
			PatchSecurity();
		}

		private void PatchSecurity()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Expected O, but got Unknown
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Expected O, but got Unknown
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Expected O, but got Unknown
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Expected O, but got Unknown
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Expected O, but got Unknown
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f5: Expected O, but got Unknown
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_0466: Unknown result type (might be due to invalid IL or missing references)
			//IL_047a: Expected O, but got Unknown
			//IL_04b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c1: Expected O, but got Unknown
			//IL_04f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0502: Expected O, but got Unknown
			//IL_056a: Unknown result type (might be due to invalid IL or missing references)
			//IL_056f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0578: Expected O, but got Unknown
			//IL_0741: Unknown result type (might be due to invalid IL or missing references)
			//IL_074e: Expected O, but got Unknown
			//IL_0782: Unknown result type (might be due to invalid IL or missing references)
			//IL_078f: Expected O, but got Unknown
			//IL_08a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b1: Expected O, but got Unknown
			//IL_091d: Unknown result type (might be due to invalid IL or missing references)
			//IL_092b: Expected O, but got Unknown
			//IL_099b: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a9: Expected O, but got Unknown
			//IL_0a19: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a27: Expected O, but got Unknown
			//IL_060b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0618: Expected O, but got Unknown
			//IL_06b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c0: Expected O, but got Unknown
			//IL_080e: Unknown result type (might be due to invalid IL or missing references)
			//IL_081c: Expected O, but got Unknown
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Expected O, but got Unknown
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Expected O, but got Unknown
			try
			{
				MethodInfo method = typeof(PlayerRepDamageMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)method, new HarmonyMethod(typeof(Core).GetMethod("DamagePrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] cheat damage guard OK");
			}
			catch (Exception ex)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] damage patch failed: " + ex.Message);
			}
			try
			{
				MethodInfo method2 = typeof(MessageHandler).GetMethod("OnPreRelayMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)method2, new HarmonyMethod(typeof(Core).GetMethod("RelayPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] host damage guard (relay) OK");
			}
			catch (Exception ex2)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] relay patch failed: " + ex2.Message);
			}
			try
			{
				MethodInfo method3 = typeof(DisconnectMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)method3, new HarmonyMethod(typeof(Core).GetMethod("DisconnectPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] fake kick guard OK");
			}
			catch (Exception ex3)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] disconnect patch failed: " + ex3.Message);
			}
			try
			{
				MethodInfo methodInfo = typeof(PlayerSender).GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo x) => x.Name == "SendPlayerDamage" && x.GetParameters().Length == 3);
				if (methodInfo != null)
				{
					((MelonBase)this).HarmonyInstance.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Core).GetMethod("SendDamagePrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				MethodInfo method4 = typeof(PlayerRepActionMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)method4, new HarmonyMethod(typeof(Core).GetMethod("ActionPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] god mode detector OK");
			}
			catch (Exception ex4)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] god mode patch failed: " + ex4.Message);
			}
			try
			{
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)typeof(EntityOwnershipRequestMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), new HarmonyMethod(typeof(Core).GetMethod("OwnershipPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)typeof(DespawnRequestMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), new HarmonyMethod(typeof(Core).GetMethod("DespawnRequestPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)typeof(PlayerRepAvatarMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), new HarmonyMethod(typeof(Core).GetMethod("AvatarPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] hijack / despawn / avatar spam guard OK");
			}
			catch (Exception ex5)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] entity patch failed: " + ex5.Message);
			}
			PatchEos();
			PatchServer6();
			PatchPoses();
			try
			{
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)typeof(GunShotMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), new HarmonyMethod(typeof(Core).GetMethod("GunShotPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)typeof(SlowMoButtonMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), new HarmonyMethod(typeof(Core).GetMethod("SlowMoPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] remote fire / forced slow-mo guard OK");
			}
			catch (Exception ex6)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] gun / slow-mo patch failed: " + ex6.Message);
			}
			try
			{
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)typeof(GunShotMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), new HarmonyMethod(typeof(Core).GetMethod("ShotWatchPrefix", BindingFlags.Static | BindingFlags.NonPublic))
				{
					priority = 200
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				shotWatchPatched = true;
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)typeof(MagazineInsertMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), new HarmonyMethod(typeof(Core).GetMethod("MagInsertPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)typeof(MagazineEjectMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), new HarmonyMethod(typeof(Core).GetMethod("MagEjectPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] Combat Guard OK (warnings: modded guns, infinite ammo)");
			}
			catch (Exception ex7)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] Combat Guard patch failed: " + ex7.Message);
			}
			try
			{
				MethodInfo method5 = typeof(MessageHandler).GetMethod("StartHandlingMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				HarmonyMethod val = new HarmonyMethod(typeof(Core).GetMethod("NetStatPrefix", BindingFlags.Static | BindingFlags.NonPublic))
				{
					priority = 0
				};
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)method5, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] network log [NET] OK");
			}
			catch (Exception ex8)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] network log patch failed: " + ex8.Message);
			}
			try
			{
				MethodInfo method6 = typeof(RigPose).GetMethod("ReadSkeleton", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method6 != null)
				{
					((MelonBase)this).HarmonyInstance.Patch((MethodBase)method6, (HarmonyMethod)null, new HarmonyMethod(typeof(Core).GetMethod("VanishPosePostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					vanishPatched = true;
					((MelonBase)this).LoggerInstance.Msg("[Security] vanish OK");
				}
				else
				{
					((MelonBase)this).LoggerInstance.Warning("[Security] RigPose.ReadSkeleton not found: vanish disabled");
				}
			}
			catch (Exception ex9)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] vanish patch failed: " + ex9.Message);
			}
			try
			{
				MethodInfo method7 = typeof(RigVoiceSource).GetMethod("UpdateVoiceSource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method7 != null)
				{
					((MelonBase)this).HarmonyInstance.Patch((MethodBase)method7, (HarmonyMethod)null, new HarmonyMethod(typeof(Core).GetMethod("VoiceRangePostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					((MelonBase)this).LoggerInstance.Msg("[Security] megaphone OK");
				}
				else
				{
					((MelonBase)this).LoggerInstance.Warning("[Security] RigVoiceSource.UpdateVoiceSource not found: megaphone disabled");
				}
			}
			catch (Exception ex10)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] megaphone patch failed: " + ex10.Message);
			}
			try
			{
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)typeof(LobbyMetadataSerializer).GetMethod("ReadInfo", BindingFlags.Static | BindingFlags.Public), (HarmonyMethod)null, new HarmonyMethod(typeof(Core).GetMethod("LobbyInfoPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)typeof(PlayerSender).GetMethod("SendPlayerTeleport", BindingFlags.Static | BindingFlags.Public), (HarmonyMethod)null, new HarmonyMethod(typeof(Core).GetMethod("TeleportPostfix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] watchlist lobbies + freeze OK");
			}
			catch (Exception ex11)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] watchlist / freeze patch failed: " + ex11.Message);
			}
			try
			{
				MethodInfo method8 = typeof(LobbyMetadataInfo).GetMethod("Write", BindingFlags.Instance | BindingFlags.Public);
				if (method8 != null)
				{
					((MelonBase)this).HarmonyInstance.Patch((MethodBase)method8, new HarmonyMethod(typeof(Core).GetMethod("LobbyWritePrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					lobbyFgPatched = true;
					((MelonBase)this).LoggerInstance.Msg("[Security] FusionGuard info in the lobby list OK");
				}
				else
				{
					((MelonBase)this).LoggerInstance.Warning("[Security] LobbyMetadataInfo.Write not found: FG info in the lobby list disabled");
				}
			}
			catch (Exception ex12)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] lobby FG info patch failed: " + ex12.Message);
			}
			try
			{
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)typeof(GamemodeTriggerResponseMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), new HarmonyMethod(typeof(Core).GetMethod("TriggerPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] fake gamemode event guard OK");
			}
			catch (Exception ex13)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] gamemode patch failed: " + ex13.Message);
			}
			try
			{
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)typeof(PlayerRepTeleportMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), new HarmonyMethod(typeof(Core).GetMethod("TeleportMsgPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] fake teleport guard OK");
			}
			catch (Exception ex14)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] teleport patch failed: " + ex14.Message);
			}
			try
			{
				MethodInfo method9 = typeof(PlayerMetadataRequestMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)method9, new HarmonyMethod(typeof(Core).GetMethod("MetadataPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] fake rank guard OK");
			}
			catch (Exception ex15)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] metadata patch failed: " + ex15.Message);
			}
			try
			{
				MethodInfo method10 = typeof(PermissionCommandRequestMessage).GetMethod("OnHandleMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				((MelonBase)this).HarmonyInstance.Patch((MethodBase)method10, new HarmonyMethod(typeof(Core).GetMethod("PermCommandPrefix", BindingFlags.Static | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((MelonBase)this).LoggerInstance.Msg("[Security] anti-kick host OK");
			}
			catch (Exception ex16)
			{
				((MelonBase)this).LoggerInstance.Warning("[Security] kick patch failed: " + ex16.Message);
			}
		}

		private static bool DamagePrefix(ReceivedMessage received)
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			if (!GuardOn)
			{
				return true;
			}
			Core instance = Instance;
			if (instance == null || !((ReceivedMessage)(ref received)).Sender.HasValue)
			{
				return true;
			}
			try
			{
				byte value = ((ReceivedMessage)(ref received)).Sender.Value;
				if (value == PlayerIDManager.LocalSmallID)
				{
					return true;
				}
				if (NetworkInfo.IsHost && instance.IsFrozen(value))
				{
					return false;
				}
				if (!instance.antiCheatDamage)
				{
					return true;
				}
				PlayerRepDamageData data = ((ReceivedMessage)(ref received)).ReadData<PlayerRepDamageData>();
				if ((Object)(object)Player.Head == (Object)null)
				{
					return true;
				}
				Vector3 position = Player.Head.position;
				if (!instance.IsCheatDamage(value, data, position, PlayerIDManager.LocalSmallID, out var reason))
				{
					return true;
				}
				instance.OnCheatDamage(value, PlayerIDManager.LocalSmallID, reason);
				return false;
			}
			catch (Exception ex)
			{
				((MelonBase)instance).LoggerInstance.Warning("[Security] DamagePrefix : " + ex.Message);
				return true;
			}
		}

		private static bool RelayPrefix(MessageHandler __instance, ReceivedMessage received, ref bool __result)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			if (!GuardOn)
			{
				return true;
			}
			Core instance = Instance;
			if (instance == null || !((ReceivedMessage)(ref received)).Sender.HasValue || !NetworkInfo.IsHost)
			{
				return true;
			}
			byte value = ((ReceivedMessage)(ref received)).Sender.Value;
			if (instance.IsFrozen(value) && (__instance is PlayerRepDamageMessage || __instance is PlayerRepGrabMessage || __instance is SlowMoButtonMessage))
			{
				__result = false;
				return false;
			}
			if (__instance is PlayerRepTeleportMessage && instance.antiFakeTp && value != PlayerIDManager.LocalSmallID)
			{
				instance.OnFakeTeleport(value);
				__result = false;
				return false;
			}
			try
			{
				if (!instance.CountMessage(value, received))
				{
					__result = false;
					return false;
				}
			}
			catch
			{
			}
			if ((__instance is PlayerPoseUpdateMessage || __instance is EntityPoseUpdateMessage) && instance.poseQuarantine.TryGetValue(value, out var value2) && Time.realtimeSinceStartup < value2)
			{
				__result = false;
				return false;
			}
			if (__instance is PlayerVoiceChatMessage && instance.VoiceMutedForAll(value))
			{
				__result = false;
				return false;
			}
			if (__instance is SlowMoButtonMessage && instance.antiSlowMo && !SlowMoAllowed(value))
			{
				instance.OnBadSlowMo(value);
				__result = false;
				return false;
			}
			if (__instance is GamemodeTriggerResponseMessage)
			{
				string text = null;
				try
				{
					text = instance.BadTrigger(value, received);
				}
				catch
				{
				}
				if (text != null)
				{
					instance.OnBadTrigger(value, text);
					__result = false;
					return false;
				}
			}
			bool flag = __instance is PlayerRepDamageMessage;
			bool flag2 = !flag && __instance is PlayerRepAvatarMessage;
			if (!flag && !flag2 && !(__instance is PlayerRepActionMessage))
			{
				return true;
			}
			try
			{
				byte b = value;
				if (flag2)
				{
					if (!instance.AvatarSpam(b))
					{
						return true;
					}
					__result = false;
					return false;
				}
				if (!flag)
				{
					instance.OnPlayerAction(b, ((ReceivedMessage)(ref received)).ReadData<PlayerRepActionData>());
					return true;
				}
				MessageRoute route = ((ReceivedMessage)(ref received)).Route;
				byte? target = ((MessageRoute)(ref route)).Target;
				if (!target.HasValue || target.Value == PlayerIDManager.LocalSmallID)
				{
					return true;
				}
				if (b == PlayerIDManager.LocalSmallID)
				{
					return true;
				}
				PlayerRepDamageData data = ((ReceivedMessage)(ref received)).ReadData<PlayerRepDamageData>();
				if (instance.antiCheatDamage && instance.TryGetHead(target.Value, out var pos) && instance.IsCheatDamage(b, data, pos, target.Value, out var reason))
				{
					instance.OnCheatDamage(b, target.Value, reason);
					__result = false;
					return false;
				}
				instance.RecordDamage(target.Value, data);
				return true;
			}
			catch (Exception ex)
			{
				((MelonBase)instance).LoggerInstance.Warning("[Security] RelayPrefix : " + ex.Message);
				return true;
			}
		}

		private static void SendDamagePrefix(byte target, Attack attack)
		{
			if (!GuardOn)
			{
				return;
			}
			Core instance = Instance;
			if (instance == null || !instance.godDetect || attack == null)
			{
				return;
			}
			try
			{
				instance.RecordDamage(target, attack.damage);
			}
			catch
			{
			}
		}

		private static void ActionPrefix(ReceivedMessage received)
		{
			if (!GuardOn)
			{
				return;
			}
			Core instance = Instance;
			if (instance == null || !((ReceivedMessage)(ref received)).Sender.HasValue)
			{
				return;
			}
			try
			{
				instance.OnPlayerAction(((ReceivedMessage)(ref received)).Sender.Value, ((ReceivedMessage)(ref received)).ReadData<PlayerRepActionData>());
			}
			catch
			{
			}
		}

		private static bool DisconnectPrefix(ReceivedMessage received)
		{
			//IL_0048: 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_0164: Unknown result type (might be due to invalid IL or missing references)
			if (!GuardOn)
			{
				return true;
			}
			Core instance = Instance;
			if (instance == null)
			{
				return true;
			}
			if (!instance.antiFakeKick)
			{
				if (!NetworkInfo.IsHost)
				{
					instance.NotifyKickSeen(received);
				}
				return true;
			}
			if (NetworkInfo.IsHost)
			{
				if (!_eosNetDisconnect || ((ReceivedMessage)(ref received)).IsServerHandled)
				{
					return true;
				}
				_eosNetDisconnect = false;
				instance.kicksBlocked++;
				instance.AddLog("Fake kick sent to the host (" + (((ReceivedMessage)(ref received)).Sender.HasValue ? GetName(PlayerIDManager.GetPlayerID(((ReceivedMessage)(ref received)).Sender.Value), ((ReceivedMessage)(ref received)).Sender.Value) : "hidden sender") + "): blocked");
				instance.SecNotify("hostkick", "/!\\ Someone tried to kick the host (fake message): blocked");
				return false;
			}
			if (!((ReceivedMessage)(ref received)).Sender.HasValue)
			{
				instance.NotifyKickSeen(received);
				return true;
			}
			try
			{
				byte value = ((ReceivedMessage)(ref received)).Sender.Value;
				PlayerID playerID = PlayerIDManager.GetPlayerID(value);
				if (playerID != null && playerID.IsHost)
				{
					instance.NotifyKickSeen(received);
					return true;
				}
				instance.kicksBlocked++;
				instance.CrashHit(value, "fake kick");
				string name = GetName(playerID, value);
				instance.AddLog(name + " sent a fake kick (blocked)");
				instance.SecNotify("fake" + value, "/!\\ " + name + " tried to kick you (fake kick blocked)");
				instance.RaiseAlert("fakekick", value, "Sent a fake kick (blocked)", null, ban: false);
				return false;
			}
			catch
			{
				return true;
			}
		}

		private void NotifyKickSeen(ReceivedMessage received)
		{
			if (!kickNotifs)
			{
				return;
			}
			try
			{
				DisconnectMessageData val = ((ReceivedMessage)(ref received)).ReadData<DisconnectMessageData>();
				if (val == null)
				{
					return;
				}
				if (_discPlatF == null)
				{
					_discPlatF = typeof(DisconnectMessageData).GetField("PlatformID", BindingFlags.Instance | BindingFlags.Public);
				}
				if (_discReasonF == null)
				{
					_discReasonF = typeof(DisconnectMessageData).GetField("Reason", BindingFlags.Instance | BindingFlags.Public);
				}
				string text = _discPlatF?.GetValue(val)?.ToString();
				string text2 = (_discReasonF?.GetValue(val) as string) ?? "";
				if (string.IsNullOrEmpty(text) || text == "0")
				{
					return;
				}
				PlayerID val2 = PlayerByPlat(text);
				if (val2 != null && !val2.IsMe)
				{
					string text3 = text2.ToLowerInvariant();
					bool flag = text3.Contains("ban");
					if (flag || text3.Contains("kick"))
					{
						string name = GetName(val2, val2.SmallID);
						AddLog(name + (flag ? " was banned" : " was kicked") + " by the host (" + text2 + ")");
						Notify(name + (flag ? " was banned from the server" : " was kicked from the server"), 3f);
					}
				}
			}
			catch
			{
			}
		}

		private static PermissionLevel LevelOf(PlayerID pid)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (pid == null)
			{
				return (PermissionLevel)0;
			}
			if (pid.IsHost)
			{
				return (PermissionLevel)2;
			}
			try
			{
				return FusionCompat.FetchPermission(FusionCompat.Plat(pid));
			}
			catch
			{
				return (PermissionLevel)0;
			}
		}

		private static bool PermCommandPrefix(ReceivedMessage received)
		{
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Invalid comparison between Unknown and I4
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Invalid comparison between Unknown and I4
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Invalid comparison between Unknown and I4
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			if (!GuardOn)
			{
				return true;
			}
			Core instance = Instance;
			if (instance == null || (!instance.antiKickServer && !instance.limitTeleports) || !NetworkInfo.IsHost || !((ReceivedMessage)(ref received)).Sender.HasValue)
			{
				return true;
			}
			try
			{
				PermissionCommandRequestData val = ((ReceivedMessage)(ref received)).ReadData<PermissionCommandRequestData>();
				if (val == null)
				{
					return true;
				}
				byte value = ((ReceivedMessage)(ref received)).Sender.Value;
				if (value == PlayerIDManager.LocalSmallID)
				{
					return true;
				}
				if ((int)val.Type == 4)
				{
					string text = FusionCompat.Plat(PlayerIDManager.GetPlayerID(value));
					if (!instance.limitTeleports || (FusionCompat.Has(text) && instance.trusted.ContainsKey(text)) || !instance.TeleportSpam(value))
					{
						return true;
					}
					instance.tpBlocked++;
					instance.CrashHit(value, "TP spam");
					if (instance.Strike(instance.tpStrikes, value, 3, 20f))
					{
						instance.NetCheat(value, "tpspam", "TP spam on other players: blocked", "TP spam on players: blocked", "Teleport spam (TP others to him)");
					}
					return false;
				}
				bool flag = (int)val.Type == 2;
				if (!flag && (int)val.Type != 1)
				{
					return true;
				}
				if (!instance.antiKickServer || !FusionCompat.PermsOk)
				{
					return true;
				}
				PlayerID playerID = PlayerIDManager.GetPlayerID(value);
				PlayerID val2 = (val.OtherPlayer.HasValue ? PlayerIDManager.GetPlayerID(val.OtherPlayer.Value) : null);
				string name = GetName(playerID, value);
				string text2 = (val.OtherPlayer.HasValue ? GetName(val2, val.OtherPlayer.Value) : "?");
				string text3 = (flag ? "ban" : "kick");
				PermissionLevel val3 = LevelOf(playerID);
				PermissionLevel val4 = (PermissionLevel)1;
				try
				{
					val4 = (flag ? LobbyInfoManager.LobbyInfo.Banning : LobbyInfoManager.LobbyInfo.Kicking);
				}
				catch
				{
				}
				PermissionLevel val5 = LevelOf(val2);
				string text4 = null;
				if (val2 == null)
				{
					text4 = "target not found";
				}
				else if (val2.IsHost || val2.IsMe)
				{
					text4 = "target is the HOST";
				}
				else if (val3 < val4)
				{
					text4 = "no permission (" + PermNames[PermIndex(val3)] + " < " + PermNames[PermIndex(val4)] + ")";
				}
				else if (val5 >= val3)
				{
					text4 = "target has same or higher rank (" + PermNames[PermIndex(val5)] + ")";
				}
				if (text4 == null && !instance.confirmOpKicks)
				{
					instance.AddLog(name + " (" + PermNames[PermIndex(val3)] + ") did " + text3 + " " + text2);
					instance.Notify(name + " used " + text3 + " on " + text2, 2.5f);
					return true;
				}
				instance.kicksBlocked++;
				if (text4 != null)
				{
					instance.CrashHit(value, "kick without perms");
				}
				string reason = ((text4 == null) ? ("Wants to " + text3 + " " + text2 + " (has perms, needs your OK)") : ("Tried to " + text3 + " " + text2 + " : " + text4));
				instance.AddLog(name + " : " + text3 + " " + text2 + " blocked" + ((text4 != null) ? (" (" + text4 + ")") : " (waiting for your OK)"));
				instance.SecNotify("kick" + value, "/!\\ " + name + " tried to " + text3 + " " + text2 + ((text4 != null) ? " without the right" : "") + ": blocked");
				SecAlert secAlert = instance.RaiseAlert((text4 == null) ? "kick" : "kickcheat", value, reason, val.OtherPlayer, flag);
				secAlert.Allowed = text4 == null;
				return false;
			}
			catch (Exception ex)
			{
				((MelonBase)instance).LoggerInstance.Warning("[Security] PermCommandPrefix : " + ex.Message);
				return true;
			}
		}

		private void BlockPeer(string plat, float secs)
		{
			if (FusionCompat.Has(plat))
			{
				float num = Time.realtimeSinceStartup + secs;
				if (!blockedPeers.TryGetValue(plat, out var value) || value < num)
				{
					blockedPeers[plat] = num;
				}
			}
		}

		private bool PeerBlocked(string plat)
		{
			if (!FusionCompat.Has(plat))
			{
				return false;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (guardBans.ContainsKey(plat))
			{
				return true;
			}
			if (tempBans.TryGetValue(plat, out var value) && realtimeSinceStartup < value)
			{
				return true;
			}
			float value2;
			return blockedPeers.TryGetValue(plat, out value2) && realtimeSinceStartup < value2;
		}

		private void DropPeerPacket(string plat, string why)
		{
			ghostDropped++;
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!peerCloseAt.TryGetValue(plat, out var value) || realtimeSinceStartup - value > 2f)
			{
				peerCloseAt[plat] = realtimeSinceStartup;
				FusionCompat.CloseConnection(plat);
			}
			ghostCount.TryGetValue(plat, out var value2);
			value2 = (ghostCount[plat] = value2 + 1);
			if (value2 >= 10 && (!ghostLogAt.TryGetValue(plat, out var value3) || realtimeSinceStartup - value3 > 30f))
			{
				ghostLogAt[plat] = realtimeSinceStartup;
				ghostCount[plat] = 0;
				AddLog("Packets from a player not in the server (" + why + "): dropped + connection closed");
				SecLog("GHOST [" + plat + "] : " + why);
			}
		}

		private static PlayerID PlayerByPlat(string plat)
		{
			if (string.IsNullOrEmpty(plat))
			{
				return null;
			}
			foreach (PlayerID item in PlayerIDManager.PlayerIDs.ToList())
			{
				if (item != null && FusionCompat.Plat(item) == plat)
				{
					return item;
				}
			}
			return null;
		}

		private static string MyPlat()
		{
			foreach (PlayerID item in PlayerIDManager.PlayerIDs.ToList())
			{
				if (item != null && item.IsMe)
				{
					return FusionCompat.Plat(item);
				}
			}
			return null;
		}

		private static string HostPlat()
		{
			foreach (PlayerID item in PlayerIDManager.PlayerIDs.ToList())
			{
				if (item != null && item.IsHost)
				{
					return FusionCompat.Plat(item);
				}
			}
			return null;
		}

		private void OnSpoof(string peer, string what)
		{
			spoofBlocked++;
			PlayerID val = PlayerByPlat(peer);
			if (val != null)
			{
				CrashHit(val.SmallID, "spoofing");
			}
			string text = peer ?? "?";
			if (!spoofStrikes.TryGetValue(text, out var value))
			{
				value = new List<float>();
				spoofStrikes[text] = value;
			}
			float now = Time.realtimeSinceStartup;
			value.Add(now);
			value.RemoveAll((float x) => now - x > 10f);
			if (value.Count == 2)
			{
				if (val != null)
				{
					NetCheat(val.SmallID, "spoof", what + ": blocked", what + " (Epic exploit): blocked", what);
					return;
				}
				AddLog("Forged packet from an unknown sender (" + text + "): " + what + ": blocked");
			}
		}

		private static bool EosProcessPrefix(object __instance, object[] __args)
		{
			if (!GuardOn)
			{
				return true;
			}
			bool flag = EosProcessCheck(__instance, __args);
			if (!flag)
			{
				ReturnEosBuffer(__instance, __args);
			}
			return flag;
		}

		private static void ReturnEosBuffer(object receiver, object[] args)
		{
			try
			{
				if (receiver != null && args != null && args.Length != 0 && args[0] is byte[] array)
				{
					if (!_poolInit)
					{
						_poolInit = true;
						_rcvP2P = receiver.GetType().GetField("P2P", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						_p2pPool = _rcvP2P?.FieldType.GetField("BufferPool", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						_poolReturn = _p2pPool?.FieldType.GetMethod("Return", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(byte[]) }, null);
					}
					object obj = _rcvP2P?.GetValue(receiver);
					object obj2 = ((obj == null) ? null : _p2pPool?.GetValue(obj));
					if (obj2 != null)
					{
						_poolReturn?.Invoke(obj2, new object[1] { array });
					}
				}
			}
			catch
			{
			}
		}

		private static string LocalEosId(object receiver)
		{
			try
			{
				if (receiver == null)
				{
					return null;
				}
				if (_rcvP2P == null)
				{
					_rcvP2P = receiver.GetType().GetField("P2P", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				object obj = _rcvP2P?.GetValue(receiver);
				if (obj == null)
				{
					return null;
				}
				if (_p2pLocalId == null)
				{
					_p2pLocalId = obj.GetType().GetField("LocalUserId", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				return _p2pLocalId?.GetValue(obj)?.ToString();
			}
			catch
			{
				return null;
			}
		}

		private static bool EosProcessCheck(object receiver, object[] __args)
		{
			_eosPeer = null;
			_eosNetDisconnect = false;
			_eosNativeCheck = false;
			Core instance = Instance;
			try
			{
				_eosPeer = __args[2]?.ToString();
				object obj = __args[3];
				bool flag = default(bool);
				int num;
				if (obj is bool)
				{
					flag = (bool)obj;
					num = 1;
				}
				else
				{
					num = 0;
				}
				_eosServerHandled = (byte)((uint)num & (flag ? 1u : 0u)) != 0;
				_eosFresh = true;
				if (instance == null || !NetworkInfo.HasServer)
				{
					return true;
				}
				string text = LocalEosId(receiver);
				if (string.IsNullOrEmpty(text))
				{
					text = MyPlat();
				}
				if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(_eosPeer) && _eosPeer == text)
				{
					_eosPeer = null;
					_eosFresh = false;
					_selfPackets++;
					if (!_selfLogged && NetworkInfo.IsHost)
					{
						_selfLogged = true;
						((MelonBase)instance).LoggerInstance.Msg("[Epic] host: your own Epic packets (the copies Fusion handles for you) are let through: OK");
					}
					return true;
				}
				bool flag2 = instance.antiSpoof || instance.antiFakeKick || instance.antiKickServer;
				if (NetworkInfo.IsHost)
				{
					if (instance.antiSpoof && instance.PeerBlocked(_eosPeer))
					{
						instance.DropPeerPacket(_eosPeer, "kicked / banned");
						return false;
					}
					if (flag2 && !_eosServerHandled)
					{
						instance.OnSpoof(_eosPeer, "Sent a fake 'server' message to the host");
						return false;
					}
				}
				else if (flag2)
				{
					if (_eosServerHandled)
					{
						instance.OnSpoof(_eosPeer, "Sent a fake 'server' packet to you");
						return false;
					}
					string text2 = HostPlat();
					if (!string.IsNullOrEmpty(text2) && !string.IsNullOrEmpty(_eosPeer) && _eosPeer != text2)
					{
						instance.OnSpoof(_eosPeer, "Sent you a packet directly (not through the host)");
						return false;
					}
				}
			}
			catch
			{
			}
			return true;
		}

		private static void EosProcessPostfix()
		{
			_eosPeer = null;
			_eosFresh = false;
			_eosNetDisconnect = false;
			_eosNativeCheck = false;
		}

		private static void BuildPlatSetter()
		{
			try
			{
				Type typeFromHandle = typeof(ReadableMessage);
				MethodInfo methodInfo = typeFromHandle.GetProperty("PlatformID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetSetMethod(nonPublic: true);
				if (!(methodInfo == null) && methodInfo.GetParameters().Length == 1 && !(methodInfo.GetParameters()[0].ParameterType != typeof(string)))
				{
					DynamicMethod dynamicMethod = new DynamicMethod("FG_FillRealSenderId", typeof(void), new Type[2]
					{
						typeFromHandle.MakeByRefType(),
						typeof(string)
					}, typeof(Core).Module, skipVisibility: true);
					ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
					iLGenerator.Emit(OpCodes.Ldarg_0);
					iLGenerator.Emit(OpCodes.Ldarg_1);
					iLGenerator.Emit(OpCodes.Call, methodInfo);
					iLGenerator.Emit(OpCodes.Ret);
					_setPlat = (PlatSetter)dynamicMethod.CreateDelegate(typeof(PlatSetter));
				}
			}
			catch (Exception ex)
			{
				_setPlat = null;
				Core instance = Instance;
				if (instance != null)
				{
					((MelonBase)instance).LoggerInstance.Warning("[Security] setter PlatformID : " + ex.Message);
				}
			}
		}

		private static void ReadMessagePrefix(ref ReadableMessage __0)
		{
			if (!GuardOn)
			{
				return;
			}
			_eosNativeCheck = false;
			Core instance = Instance;
			if (instance == null || !instance.antiSpoof || _setPlat == null || !_eosFresh || string.IsNullOrEmpty(_eosPeer) || !NetworkInfo.IsHost)
			{
				return;
			}
			try
			{
				if (((ReadableMessage)(ref __0)).IsServerHandled && PlayerByPlat(_eosPeer) != null)
				{
					_setPlat(ref __0, _eosPeer);
					_eosNativeCheck = true;
				}
			}
			catch
			{
			}
		}

		private static void ReadMessagePostfix()
		{
			_eosNativeCheck = false;
		}

		private static void NativeDisconnectPrefix(object __0)
		{
			if (!GuardOn || !_eosNativeCheck)
			{
				return;
			}
			Core instance = Instance;
			if (instance == null)
			{
				return;
			}
			try
			{
				string text = __0?.ToString();
				if (!string.IsNullOrEmpty(text) && !(text != _eosPeer))
				{
					_eosNativeCheck = false;
					instance.spoofBlocked++;
					instance.BlockPeer(text, 60f);
					PlayerID val = PlayerByPlat(text);
					string text2 = ((val != null) ? GetName(val, val.SmallID) : text);
					instance.AddLog(text2 + " pretended to be another player: disconnected by Fusion (check re-enabled)");
					instance.SecNotify("spoofnative" + text, "/!\\ " + text2 + " tried to pretend to be another player: disconnected");
					instance.SecLog("SPOOF (native) [" + text + "] → disconnected");
					if (val != null)
					{
						instance.RaiseAlert("spoof", val.SmallID, "Pretended to be another player (disconnected)", null, ban: false);
					}
				}
			}
			catch
			{
			}
		}

		private static bool EosIncomingPrefix(object[] __args)
		{
			if (!GuardOn)
			{
				return true;
			}
			Core instance = Instance;
			if (instance == null || !instance.antiSpoof || __args == null || __args.Length == 0)
			{
				return true;
			}
			try
			{
				object obj = __args[0];
				string text = obj?.GetType().GetProperty("RemoteUserId")?.GetValue(obj)?.ToString();
				if (string.IsNullOrEmpty(text) || !instance.PeerBlocked(text))
				{
					return true;
				}
				instance.ghostDropped++;
				if (instance.guardBans.TryGetValue(text, out var value))
				{
					instance.WarnBannedJoin(text, value.Name, "P2P refused");
				}
				if (!instance.ghostLogAt.TryGetValue(text, out var value2) || Time.realtimeSinceStartup - value2 > 30f)
				{
					instance.ghostLogAt[text] = Time.realtimeSinceStartup;
					instance.AddLog("P2P connection refused (banned / recently kicked) [" + text + "]");
				}
				return false;
			}
			catch
			{
				return true;
			}
		}

		private static bool StartHandlingPrefix(MessageHandler __instance, ReceivedMessage received)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (!GuardOn)
			{
				_fgDropped = false;
				return true;
			}
			bool flag = StartHandlingCheck(__instance, received);
			_fgDropped = !flag;
			return flag;
		}

		private static bool StartHandlingCheck(MessageHandler __instance, ReceivedMessage received)
		{
			Core instance = Instance;
			_eosNativeCheck = false;
			string eosPeer = _eosPeer;
			if (eosPeer == null || !_eosFresh)
			{
				_eosNetDisconnect = false;
				return true;
			}
			_eosFresh = false;
			_eosNetDisconnect = __instance is DisconnectMessage;
			if (instance == null || !instance.antiSpoof || !NetworkInfo.IsHost || !((ReceivedMessage)(ref received)).IsServerHandled)
			{
				return true;
			}
			try
			{
				if (__instance is ConnectionRequestMessage)
				{
					instance.joinGrace[eosPeer] = Time.realtimeSinceStartup;
					if (_backupIdField == null)
					{
						_backupIdField = typeof(ConnectionRequestData).GetField("BackupPlatformID", BindingFlags.Instance | BindingFlags.Public);
					}
					ConnectionRequestData obj = ((ReceivedMessage)(ref received)).ReadData<ConnectionRequestData>();
					string text = _backupIdField?.GetValue(obj)?.ToString();
					if (!string.IsNullOrEmpty(text) && text != eosPeer)
					{
						instance.spoofBlocked++;
						instance.AddLog("Connection refused: a player pretended to be " + text + " (real ID " + eosPeer + ")");
						instance.Notify("/!\\ Someone tried to join with another player's ID (perm theft / ban evasion): blocked", 4f);
						return false;
					}
					return true;
				}
				PlayerID val = PlayerByPlat(eosPeer);
				if (val != null)
				{
					eosIdsMatch = true;