Decompiled source of LobbyGuard v0.2.4

plugins/com.github.lethalcompanymodding.lobbyguard.dll

Decompiled 10 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using Dissonance;
using Dissonance.Integrations.Unity_NFGO;
using Dissonance.Networking;
using Dissonance.Networking.Server;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
using MonoMod.Utils;
using Netcode.Transports.Facepunch;
using Steamworks;
using Steamworks.Data;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LethalCompanyModding")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 LethalCompanyModding Contributors")]
[assembly: AssemblyFileVersion("0.2.4.0")]
[assembly: AssemblyInformationalVersion("0.2.4+56a63b59875acf955589965b66c637d6fc800825")]
[assembly: AssemblyProduct("com.github.lethalcompanymodding.lobbyguard")]
[assembly: AssemblyTitle("LobbyGuard")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/LethalCompanyModding/LobbyGuard")]
[assembly: InternalsVisibleTo("LobbyGuard.Tests")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.4.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsUnmanagedAttribute : Attribute
	{
	}
	[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 LobbyGuard
{
	internal static class Approval
	{
		private delegate void Orig(GameNetworkManager self, ConnectionApprovalRequest request, ConnectionApprovalResponse response);

		private static Hook? hook;

		public static void Hook()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			hook = new Hook((MethodBase)typeof(GameNetworkManager).GetMethod("ConnectionApproval", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic), typeof(Approval).GetMethod("Approve", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
		}

		private static void Approve(Orig orig, GameNetworkManager self, ConnectionApprovalRequest request, ConnectionApprovalResponse response)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			NetworkManager singleton = NetworkManager.Singleton;
			ulong num = ((request.ClientNetworkId == singleton.LocalClientId) ? 0 : Plugin.SteamIdOf(singleton, request.ClientNetworkId));
			if (num == 0L || (Object)(object)StartOfRound.Instance == (Object)null || !StartOfRound.Instance.KickedClientIds.Contains(num))
			{
				orig(self, request, response);
				return;
			}
			Plugin.Log.LogWarning((object)$"Turned away Steam user {num}: kicked earlier");
			response.Reason = "You cannot rejoin after being kicked.";
			response.CreatePlayerObject = false;
			response.Approved = false;
			response.Pending = false;
		}
	}
	internal static class Batch
	{
		private const ushort Magic = 4448;

		private const int HeaderSize = 16;

		public unsafe static string? Check(ArraySegment<byte> data, Func<ArraySegment<byte>, ulong> hash, uint? connectRequest = null)
		{
			if (data.Array == null || data.Count < 16)
			{
				return "packet too short";
			}
			fixed (byte* array = data.Array)
			{
				byte* ptr = array + data.Offset;
				if (*(ushort*)ptr != 4448 || ((int*)ptr)[1] != data.Count)
				{
					return "not a Netcode packet";
				}
				if (hash(new ArraySegment<byte>(data.Array, data.Offset + 16, data.Count - 16)) != (ulong)((long*)ptr)[1])
				{
					return "packet hash doesn't match";
				}
				int pos = 16;
				for (int i = 0; i < ((ushort*)ptr)[1]; i++)
				{
					if (!Packed(ptr, data.Count, ref pos, out var value) || !Packed(ptr, data.Count, ref pos, out var value2))
					{
						return "bad message header";
					}
					if (value2 > (uint)(data.Count - pos))
					{
						return "message bigger than its packet";
					}
					if (value == connectRequest && !ConnectionData(ptr, pos, pos + (int)value2))
					{
						return "bad connection request";
					}
					pos += (int)value2;
				}
			}
			return null;
		}

		private unsafe static bool ConnectionData(byte* p, int pos, int end)
		{
			if (!Packed(p, end, ref pos, out var value))
			{
				return false;
			}
			int num = (int)((value >> 1) ^ (0 - (value & 1)));
			for (int i = 0; i < num; i++)
			{
				pos += 4;
				if (pos > end || !Packed(p, end, ref pos, out var _))
				{
					return false;
				}
			}
			if (end - pos < 12)
			{
				return false;
			}
			int num2 = ((int*)(p + pos))[2];
			if (num2 >= 0)
			{
				return num2 <= end - pos - 12;
			}
			return false;
		}

		private unsafe static bool Packed(byte* p, int length, ref int pos, out uint value)
		{
			value = 0u;
			if (pos >= length)
			{
				return false;
			}
			int num = p[pos] & 7;
			if (num == 0 || num > 5 || num > length - pos)
			{
				return false;
			}
			if (num == 5)
			{
				value = (uint)(p[pos + 1] | (p[pos + 2] << 8) | (p[pos + 3] << 16) | (p[pos + 4] << 24));
			}
			else
			{
				for (int i = 0; i < num; i++)
				{
					value |= (uint)(p[pos + i] << 8 * i);
				}
				value >>= 3;
			}
			pos += num;
			return true;
		}
	}
	internal static class Lengths
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Manipulator <0>__Guard;
		}

		private const BindingFlags Statics = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly List<ILHook> hooks = new List<ILHook>();

		private static readonly MethodInfo check = typeof(Lengths).GetMethod("Check", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);

		public static void HookAll()
		{
			AppDomain.CurrentDomain.AssemblyLoad += delegate(object _, AssemblyLoadEventArgs e)
			{
				Hook(e.LoadedAssembly);
			};
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Hook(assembly);
			}
		}

		public static bool Fits(int count, int size, int remaining)
		{
			if (count >= 0)
			{
				return (long)count * (long)size <= remaining;
			}
			return false;
		}

		private unsafe static void Check(ref FastBufferReader reader, int size, __RpcParams rpc)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			int num = ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position - 4;
			if (num < 0 || Fits(*(int*)((FastBufferReader)(ref reader)).GetUnsafePtrAtCurrentPosition(), size, num))
			{
				return;
			}
			ulong senderClientId = rpc.Server.Receive.SenderClientId;
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton != (Object)null && singleton.IsServer && senderClientId != 0L)
			{
				Plugin.Kick(singleton, senderClientId, "RPC array longer than its message");
			}
			throw new OverflowException("RPC array longer than its message");
		}

		private static void Hook(Assembly assembly)
		{
			try
			{
				HookTypes(assembly);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Skipped RPC length checks in " + assembly.GetName().Name + ": " + ex.Message));
			}
		}

		private static void HookTypes(Assembly assembly)
		{
			if (assembly.IsDynamic || assembly == typeof(NetworkBehaviour).Assembly || !References(assembly))
			{
				return;
			}
			Type[] types;
			try
			{
				types = assembly.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				types = ex.Types;
			}
			Type[] array = types;
			foreach (Type type in array)
			{
				if (type == null || !Derives(type, typeof(NetworkBehaviour)))
				{
					continue;
				}
				try
				{
					hooks.AddRange((from handler in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
						where handler.Name.StartsWith("__rpc_handler_", StringComparison.Ordinal) && ReadsLength(handler)
						select handler).Select((Func<MethodInfo, ILHook>)delegate(MethodInfo handler)
					{
						//IL_001c: Unknown result type (might be due to invalid IL or missing references)
						//IL_0022: Expected O, but got Unknown
						//IL_0011: Unknown result type (might be due to invalid IL or missing references)
						//IL_0016: Unknown result type (might be due to invalid IL or missing references)
						//IL_001c: Expected O, but got Unknown
						object obj = <>O.<0>__Guard;
						if (obj == null)
						{
							Manipulator val = Guard;
							<>O.<0>__Guard = val;
							obj = (object)val;
						}
						return new ILHook((MethodBase)handler, (Manipulator)obj);
					}));
				}
				catch (Exception e) when (Missing(e))
				{
				}
			}
		}

		internal static bool Derives(Type type, Type from)
		{
			try
			{
				return from.IsAssignableFrom(type);
			}
			catch (Exception e) when (Missing(e))
			{
				return false;
			}
		}

		private static bool Missing(Exception e)
		{
			if (e is TypeLoadException || e is FileNotFoundException || e is FileLoadException)
			{
				return true;
			}
			return false;
		}

		private static bool References(Assembly assembly)
		{
			return assembly.GetReferencedAssemblies().Any((AssemblyName a) => a.Name == typeof(NetworkBehaviour).Assembly.GetName().Name);
		}

		private static bool ReadsLength(MethodInfo handler)
		{
			byte[] array = handler.GetMethodBody()?.GetILAsByteArray();
			if (array == null)
			{
				return false;
			}
			for (int i = 0; i + 4 < array.Length; i++)
			{
				if (array[i] != 40)
				{
					continue;
				}
				try
				{
					if (ElementSize(handler.Module.ResolveMethod(BitConverter.ToInt32(array, i + 1))).HasValue)
					{
						return true;
					}
				}
				catch (ArgumentException)
				{
				}
			}
			return false;
		}

		private static void Guard(ILContext il)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			ParameterDefinition val = ((MethodReference)il.Method).Parameters[1];
			ParameterDefinition val2 = ((MethodReference)il.Method).Parameters[2];
			ILCursor val3 = new ILCursor(il);
			while (val3.TryGotoNext((MoveType)0, new Func<Instruction, bool>[1]
			{
				(Instruction i) => i.OpCode == OpCodes.Call && i.Operand is MethodReference
			}))
			{
				MethodBase read = null;
				try
				{
					read = ReflectionHelper.ResolveReflection((MethodReference)val3.Next.Operand);
				}
				catch (Exception)
				{
				}
				int? num = ElementSize(read);
				if (num.HasValue)
				{
					int valueOrDefault = num.GetValueOrDefault();
					val3.Emit(OpCodes.Ldarga, val);
					val3.Emit(OpCodes.Ldc_I4, valueOrDefault);
					val3.Emit(OpCodes.Ldarg, val2);
					val3.Emit(OpCodes.Call, (MethodBase)check);
				}
				int index = val3.Index;
				val3.Index = index + 1;
			}
		}

		private static int? ElementSize(MethodBase? read)
		{
			if (read?.DeclaringType != typeof(FastBufferReader) || !read.Name.StartsWith("Read", StringComparison.Ordinal))
			{
				return null;
			}
			ParameterInfo[] parameters = read.GetParameters();
			if (parameters.Length == 0 || !parameters[0].ParameterType.IsByRef)
			{
				return null;
			}
			Type elementType = parameters[0].ParameterType.GetElementType();
			if (elementType == typeof(string))
			{
				return 1;
			}
			Type type = (elementType.IsArray ? elementType.GetElementType() : ((elementType.IsGenericType && elementType.GetGenericTypeDefinition().FullName == "Unity.Collections.NativeArray`1") ? elementType.GetGenericArguments()[0] : null));
			if (type == null)
			{
				return null;
			}
			if (!type.IsValueType || typeof(INetworkSerializable).IsAssignableFrom(type))
			{
				return 1;
			}
			return (int)typeof(Lengths).GetMethod("SizeOf", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).MakeGenericMethod(type).Invoke(null, null);
		}

		private unsafe static int SizeOf<T>() where T : unmanaged
		{
			return sizeof(T);
		}
	}
	[BepInPlugin("com.github.lethalcompanymodding.lobbyguard", "LobbyGuard", "0.2.4")]
	[BepInProcess("Lethal Company.exe")]
	public class Plugin : BaseUnityPlugin
	{
		private delegate void DataEvent(NetworkConnectionManager self, ulong transportId, ref ArraySegment<byte> payload, float receiveTime);

		private const int MaxPacketsPerSecond = 2000;

		private const int MaxMessagesPerSecond = 20000;

		private static readonly Dictionary<ulong, (float Start, int Packets, int Messages)> rates = new Dictionary<ulong, (float, int, int)>();

		private Hook? hook;

		internal static ManualLogSource Log { get; private set; } = null;

		private void Awake()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			hook = new Hook((MethodBase)typeof(NetworkConnectionManager).GetMethod("DataEventHandler", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic), typeof(Plugin).GetMethod("OnData", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
			Lengths.HookAll();
			Approval.Hook();
			Voice.Hook();
			Vanilla.Hook();
			Log.LogInfo((object)"LobbyGuard 0.2.4 loaded");
		}

		private static void OnData(DataEvent orig, NetworkConnectionManager self, ulong transportId, ref ArraySegment<byte> payload, float receiveTime)
		{
			ulong value;
			if (!self.LocalClient.IsServer)
			{
				orig(self, transportId, ref payload, receiveTime);
			}
			else if (self.TransportIdToClientIdMap.TryGetValue(transportId, out value))
			{
				uint? connectRequest = (self.NetworkManager.NetworkConfig.ConnectionApproval ? new uint?(self.MessageManager.GetMessageType(typeof(ConnectionRequestMessage))) : ((uint?)null));
				string text = Batch.Check(payload, Hash, connectRequest) ?? (Flooding(transportId, BitConverter.ToUInt16(payload.Array, payload.Offset + 2)) ? "too many packets or messages" : null);
				if (text == null)
				{
					orig(self, transportId, ref payload, receiveTime);
					return;
				}
				rates.Remove(transportId);
				Kick(self.NetworkManager, value, text);
			}
		}

		internal static void Kick(NetworkManager manager, ulong clientId, string why)
		{
			ulong num = SteamIdOf(manager, clientId);
			Log.LogWarning((object)("Disconnected " + ((num != 0L) ? $"Steam user {num}" : $"client {clientId}") + ": " + why));
			manager.DisconnectClient(clientId);
		}

		internal static ulong SteamIdOf(NetworkManager manager, ulong clientId)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			ConnectionInfo val = default(ConnectionInfo);
			NetworkTransport networkTransport = manager.NetworkConfig.NetworkTransport;
			FacepunchTransport val2 = (FacepunchTransport)(object)((networkTransport is FacepunchTransport) ? networkTransport : null);
			if (val2 == null || !val2.connectedClients.TryGetValue(manager.ConnectionManager.ClientIdToTransportId(clientId), out var value) || !SteamNetworkingSockets.Internal.GetConnectionInfo(value.connection, ref val) || !((NetIdentity)(ref val.identity)).IsSteamId)
			{
				return 0uL;
			}
			return ((NetIdentity)(ref val.identity)).SteamId.Value;
		}

		private unsafe static ulong Hash(ArraySegment<byte> body)
		{
			fixed (byte* array = body.Array)
			{
				return XXHash.Hash64(array + body.Offset, body.Count, 0u);
			}
		}

		private static bool Flooding(ulong transportId, int messages)
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			float item;
			int num;
			int num2;
			if (rates.TryGetValue(transportId, out (float, int, int) value) && realtimeSinceStartup - value.Item1 < 1f)
			{
				(item, num, num2) = value;
			}
			else
			{
				num2 = 0;
				num = 0;
				item = realtimeSinceStartup;
			}
			rates[transportId] = (item, ++num, num2 += messages);
			if (num <= 2000)
			{
				return num2 > 20000;
			}
			return true;
		}
	}
	internal static class Vanilla
	{
		private delegate void Orig(GameNetworkManager self, Result result, Lobby lobby);

		private static Hook? hook;

		public static void Hook()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			hook = new Hook((MethodBase)typeof(GameNetworkManager).GetMethod("SteamMatchmaking_OnLobbyCreated", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic), typeof(Vanilla).GetMethod("Created", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
		}

		private static void Created(Orig orig, GameNetworkManager self, Result result, Lobby lobby)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			orig(self, result, lobby);
			if ((int)result == 1)
			{
				((Lobby)(ref lobby)).SetData("dmods", "f");
			}
		}
	}
	internal static class Voice
	{
		private delegate void Orig(BroadcastingClientCollection<NfgoConn> self, NfgoConn source, ref PacketReader reader);

		private static readonly int[] opusFrameSizes = new int[6] { 120, 240, 480, 960, 1920, 2880 };

		private static Hook? handshake;

		private static Hook? state;

		public static void Hook()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Expected O, but got Unknown
			Type typeFromHandle = typeof(BroadcastingClientCollection<NfgoConn>);
			handshake = new Hook((MethodBase)typeFromHandle.GetMethod("ProcessHandshakeRequest", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic), typeof(Voice).GetMethod("Handshake", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
			state = new Hook((MethodBase)typeFromHandle.GetMethod("ProcessClientState", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic), typeof(Voice).GetMethod("State", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
		}

		public static bool Allowed(byte codec, uint frameSize, int sampleRate)
		{
			return codec switch
			{
				1 => sampleRate == 48000 && Array.IndexOf(opusFrameSizes, (int)frameSize) >= 0, 
				0 => sampleRate == 44100 && frameSize == 441, 
				_ => false, 
			};
		}

		private static void Handshake(Orig orig, BroadcastingClientCollection<NfgoConn> self, NfgoConn source, ref PacketReader reader)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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)
			PacketReader copy = reader;
			if (Check(source, delegate
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				string text = default(string);
				CodecSettings result = default(CodecSettings);
				((PacketReader)(ref copy)).ReadHandshakeRequest(ref text, ref result);
				return result;
			}))
			{
				orig(self, source, ref reader);
			}
		}

		private static void State(Orig orig, BroadcastingClientCollection<NfgoConn> self, NfgoConn source, ref PacketReader reader)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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)
			PacketReader copy = reader;
			if (Check(source, delegate
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				ClientInfo val = ((PacketReader)(ref copy)).ReadClientStateHeader();
				return ((ClientInfo)(ref val)).CodecSettings;
			}))
			{
				orig(self, source, ref reader);
			}
		}

		private static bool Check(NfgoConn source, Func<CodecSettings> read)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected I4, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			string text;
			try
			{
				CodecSettings val = read();
				if (Allowed((byte)(int)((CodecSettings)(ref val)).Codec, ((CodecSettings)(ref val)).FrameSize, ((CodecSettings)(ref val)).SampleRate))
				{
					return true;
				}
				text = "bad voice codec settings";
			}
			catch (Exception)
			{
				text = "broken voice packet";
			}
			NetworkManager singleton = NetworkManager.Singleton;
			if ((Object)(object)singleton != (Object)null && singleton.IsServer && source.ClientId != singleton.LocalClientId)
			{
				Plugin.Kick(singleton, source.ClientId, text);
			}
			else
			{
				Plugin.Log.LogWarning((object)("Dropped a voice packet from this game: " + text));
			}
			return false;
		}
	}
	internal static class MyPluginInfo
	{
		public const string Id = "com.github.lethalcompanymodding.lobbyguard";

		public const string Name = "LobbyGuard";

		public const string Version = "0.2.4";
	}
}