Decompiled source of MoreBopl v2.1.1

BepInEx/plugins/MoreBopl.dll

Decompiled 3 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using HarmonyLib.Tools;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using Steamworks;
using Steamworks.Data;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")]
[assembly: AssemblyCompany("MoreMultiPlayer")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("My first plugin")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MoreMultiPlayer")]
[assembly: AssemblyTitle("MoreMultiPlayer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MoreMultiPlayer
{
	[HarmonyPatch(typeof(CharacterSelectHandler_online))]
	[HarmonyPatch("ForceStartGame")]
	public static class CharacterSelecterHandler_online_ForceStartGamePatch
	{
		[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPatch(typeof(CharacterSelectHandler_online), "InitPlayer")]
		public static Player InitPlayer(int id, byte color, byte team, byte ability1, byte ability2, byte ability3, int nrOfAbilities, PlayerColors playerColors)
		{
			throw new NotImplementedException("It's a stub");
		}

		public static bool Prefix([CanBeNull] PlayerColors pcs)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			CharacterSelectHandler_online val = AccessTools.StaticFieldRefAccess<CharacterSelectHandler_online, CharacterSelectHandler_online>("selfRef");
			if ((Object)(object)pcs == (Object)null)
			{
				pcs = val.playerColors;
			}
			MultiStartRequestPacket startParameters = SteamManagerExtended.startParameters;
			Updater.ReInit();
			List<Player> list = new List<Player>();
			Updater.InitSeed(startParameters.seed);
			Plugin.Log.LogInfo((object)$"SteamID: {SteamClient.SteamId}");
			for (int i = 0; i < startParameters.nrOfPlayers; i++)
			{
				Plugin.Log.LogInfo((object)$"Initializing player {i}: [id: {startParameters.p_ids[i]}, color: {startParameters.p_colors[i]}, team: {startParameters.p_teams[i]}, ability1: {startParameters.p_ability1s[i]}, ability2: {startParameters.p_ability2s[i]}, ability3: {startParameters.p_ability3s[i]}]");
				list.Add(InitPlayer(i + 1, startParameters.p_colors[i], startParameters.p_teams[i], startParameters.p_ability1s[i], startParameters.p_ability2s[i], startParameters.p_ability3s[i], startParameters.nrOfAbilites, pcs));
			}
			Player val2 = null;
			if (GameLobby.isPlayingAReplay)
			{
				for (int j = 0; j < list.Count; j++)
				{
					if (list[j].Id == 1)
					{
						val2 = list[j];
						break;
					}
				}
			}
			else
			{
				int num = Array.IndexOf(startParameters.p_ids, SteamId.op_Implicit(SteamClient.SteamId));
				Plugin.Log.LogInfo((object)("SteamIdIndex: " + num));
				if (num != -1)
				{
					val2 = list[num];
				}
			}
			if (val2 == null)
			{
				Plugin.Log.LogError((object)"Failed to find local player on ForceStart.");
				return false;
			}
			for (int k = 0; k < list.Count; k++)
			{
				list[k].steamId = SteamId.op_Implicit(startParameters.p_ids[k]);
			}
			val2.IsLocalPlayer = true;
			val2.inputDevice = CharacterSelectHandler_online.localPlayerInit.inputDevice;
			val2.UsesKeyboardAndMouse = CharacterSelectHandler_online.localPlayerInit.usesKeyboardMouse;
			val2.CustomKeyBinding = CharacterSelectHandler_online.localPlayerInit.keybindOverride;
			CharacterSelectHandler_online.startButtonAvailable = false;
			PlayerHandler.Get().SetPlayerList(list);
			SteamManager.instance.StartHostedGame();
			AudioManager obj = AudioManager.Get();
			if (obj != null)
			{
				obj.Play("startGame");
			}
			GameSession.Init();
			if (GameLobby.isPlayingAReplay)
			{
				SceneManager.LoadScene(startParameters.currentLevel + 6);
			}
			else
			{
				SceneManager.LoadScene("Level1");
			}
			if (!WinnerTriangleCanvas.HasBeenSpawned)
			{
				SceneManager.LoadScene("winnerTriangle", (LoadSceneMode)1);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(GameSessionHandler))]
	[HarmonyPatch("LoadNextLevelScene")]
	public class GameSessionHandlerPatch_LoadNextLevelScene
	{
		[HarmonyTranspiler]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			Plugin.Log.LogInfo((object)"Patching GameSessionHandler.LoadNextLevelScene");
			FieldInfo fromA = AccessTools.Field(typeof(SteamManager), "startParameters");
			FieldInfo toA = AccessTools.Field(typeof(SteamManagerExtended), "startParameters");
			FieldInfo fromB = AccessTools.Field(typeof(StartRequestPacket), "seed");
			FieldInfo toB = AccessTools.Field(typeof(MultiStartRequestPacket), "seed");
			return Plugin.PatchFieldLoad(fromA, fromB, toA, toB, instructions);
		}
	}
	[HarmonyPatch(typeof(GameSessionHandler))]
	[HarmonyPatch("SpawnPlayers")]
	public class GameSessionHandlerPatch_SpawnPlayers
	{
		private static void Prefix()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			List<Player> list = PlayerHandler.Get().PlayerList();
			Plugin.Log.LogInfo((object)$"Spawning {list.Count} players:");
			foreach (Player item in list)
			{
				Plugin.Log.LogInfo((object)$"Player {item.Id} ({item.steamId})");
			}
		}
	}
	public class HostPatch
	{
		public static Queue<MultiInputPacket> InputBuffer = new Queue<MultiInputPacket>();

		public static MultiInputPacket previousInputPacket;

		public static uint GetMaxSeqNumber(MultiInputPacket packet)
		{
			return (packet.inputPackets.Count != 0) ? packet.inputPackets.Max((KeyValuePair<int, InputPacket> p) => p.Value.seqNumber) : 0u;
		}

		public static int GetMaxPreviousTargetDelayBufferSize()
		{
			return (previousInputPacket.inputPackets.Count != 0) ? previousInputPacket.inputPackets.Max((KeyValuePair<int, InputPacket> p) => p.Value.targetDelayBufferSize) : 0;
		}
	}
	[HarmonyPatch(typeof(Host))]
	[HarmonyPatch("Start")]
	public class HostPatch_Start
	{
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			Plugin.Log.LogInfo((object)"Patching Host.Start");
			FieldInfo fromA = AccessTools.Field(typeof(SteamManager), "startParameters");
			FieldInfo toA = AccessTools.Field(typeof(SteamManagerExtended), "startParameters");
			FieldInfo fromB = AccessTools.Field(typeof(StartRequestPacket), "nrOfAbilites");
			FieldInfo toB = AccessTools.Field(typeof(MultiStartRequestPacket), "nrOfAbilites");
			return Plugin.PatchFieldLoad(fromA, fromB, toA, toB, instructions);
		}
	}
	[HarmonyPatch(typeof(Host))]
	[HarmonyPatch("ReInit")]
	public class HostPatch_ReInit
	{
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			Plugin.Log.LogInfo((object)"Patching Host.ReInit");
			FieldInfo fromA = AccessTools.Field(typeof(SteamManager), "startParameters");
			FieldInfo toA = AccessTools.Field(typeof(SteamManagerExtended), "startParameters");
			FieldInfo fromB = AccessTools.Field(typeof(StartRequestPacket), "frameBufferSize");
			FieldInfo toB = AccessTools.Field(typeof(MultiStartRequestPacket), "frameBufferSize");
			return Plugin.PatchFieldLoad(fromA, fromB, toA, toB, instructions);
		}
	}
	[HarmonyPatch(typeof(Host))]
	[HarmonyPatch("Init")]
	public class HostPatch_Init
	{
		public static void Prefix()
		{
			Plugin.Log.LogInfo((object)"Host::Init::Prefix");
			HostPatch.previousInputPacket = new MultiInputPacket();
		}
	}
	[HarmonyPatch(typeof(Host))]
	[HarmonyPatch("ProcessNetworkPackets")]
	public class HostPatch_ProcessNetworkPackets
	{
		private static void AddDefaultPacket()
		{
			Plugin.Log.LogInfo((object)"Adding default packet");
			HostPatch.InputBuffer.Enqueue(new MultiInputPacket());
		}

		private static void AddInputPacket(List<Client> clients, Queue<InputPacket> sentPacketHistory, int localPlayerId)
		{
			//IL_0021: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			MultiInputPacket item = new MultiInputPacket();
			foreach (Client client in clients)
			{
				InputPacket value = client.inputHistory.Dequeue();
				item.inputPackets.Add(client.PlayerId, value);
			}
			item.inputPackets.Add(localPlayerId, sentPacketHistory.Dequeue());
			HostPatch.InputBuffer.Enqueue(item);
		}

		private static IEnumerable<CodeInstruction> DebugLogInstructions(string message)
		{
			yield return new CodeInstruction(OpCodes.Ldstr, (object)message);
			yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(HostPatch_ProcessNetworkPackets), "LogText", (Type[])null, (Type[])null));
		}

		private static void LogText(string message)
		{
			Plugin.Log.LogInfo((object)message);
		}

		[HarmonyDebug]
		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			Plugin.Log.LogInfo((object)"Patching Host.ProcessNetworkPackets");
			FieldInfo delayBufferSizeFieldInfo = AccessTools.Field(typeof(Host), "delayBufferSize");
			FieldInfo updatesPlacedInDelayBufferFieldInfo = AccessTools.Field(typeof(Host), "UpdatesPlacedInDelayBuffer");
			IEnumerator<CodeInstruction> enumerator = instructions.GetEnumerator();
			Label? last_br = null;
			Label? blabel = default(Label?);
			while (enumerator.MoveNext())
			{
				CodeInstruction instruction = enumerator.Current;
				if (CodeInstructionExtensions.Branches(instruction, ref blabel))
				{
					last_br = blabel;
				}
				if (instruction.opcode == OpCodes.Ldloca_S)
				{
					CodeInstruction loopStart = instruction;
					List<Label> labels = CodeInstructionExtensions.ExtractLabels(loopStart);
					List<CodeInstruction> instructionsSkipped = new List<CodeInstruction> { loopStart };
					if (labels.Count == 0)
					{
						yield return loopStart;
						continue;
					}
					if (!enumerator.MoveNext())
					{
						Plugin.Log.LogError((object)"Expected to find next instruction after Ldloca_S");
						yield return loopStart;
						yield break;
					}
					CodeInstruction nextInstruction = enumerator.Current;
					instructionsSkipped.Add(nextInstruction);
					if (CodeInstructionExtensions.Is(nextInstruction, OpCodes.Initobj, (MemberInfo)typeof(InputPacketQuad)))
					{
						Plugin.Log.LogInfo((object)"Found possible start of loop. Searching for end...");
						bool foundEnd = false;
						while (enumerator.MoveNext())
						{
							CodeInstruction instructionA = enumerator.Current;
							instructionsSkipped.Add(instructionA);
							if (instructionA.opcode == OpCodes.Blt && labels.Contains((Label)instructionA.operand))
							{
								Plugin.Log.LogInfo((object)"Found End of loop");
								foundEnd = true;
								break;
							}
						}
						if (foundEnd)
						{
							if (!last_br.HasValue)
							{
								Plugin.Log.LogError((object)"What this shouldn't be null?!");
							}
							if (instructionsSkipped.Any((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, delayBufferSizeFieldInfo, false)))
							{
								Plugin.Log.LogInfo((object)"Found 'fill InputBuffer with default InputPacket' loop");
								Label label2 = generator.DefineLabel();
								yield return CodeInstructionExtensions.WithLabels(CodeInstruction.Call(typeof(HostPatch_ProcessNetworkPackets), "AddDefaultPacket", (Type[])null, (Type[])null), new Label[1] { label2 });
								yield return new CodeInstruction(OpCodes.Ldloc_3, (object)null);
								yield return new CodeInstruction(OpCodes.Ldc_I4_1, (object)null);
								yield return new CodeInstruction(OpCodes.Add, (object)null);
								yield return new CodeInstruction(OpCodes.Stloc_3, (object)null);
								yield return CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Ldloc_3, (object)null), new Label[1] { last_br.Value });
								yield return new CodeInstruction(OpCodes.Ldsfld, (object)AccessTools.Field(typeof(Host), "delayBufferSize"));
								yield return new CodeInstruction(OpCodes.Blt_S, (object)label2);
							}
							else if (instructionsSkipped.Any((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, updatesPlacedInDelayBufferFieldInfo, false)))
							{
								object local_i = instructionsSkipped[instructionsSkipped.Count - 3].operand;
								object local_m = instructionsSkipped[instructionsSkipped.Count - 2].operand;
								Plugin.Log.LogInfo((object)$"Local_i: {local_i}");
								Plugin.Log.LogInfo((object)$"Local_m: {local_m}");
								Plugin.Log.LogInfo((object)"Found InputPacket creation loop");
								Label label = generator.DefineLabel();
								yield return CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Ldarg_0, (object)null), new Label[1] { label });
								yield return new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Host), "clients"));
								yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
								yield return new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Host), "sentPacketHistory"));
								yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
								yield return new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Host), "localPlayerId"));
								yield return CodeInstruction.Call(typeof(HostPatch_ProcessNetworkPackets), "AddInputPacket", (Type[])null, (Type[])null);
								yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
								yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
								yield return new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Host), "UpdatesPlacedInDelayBuffer"));
								yield return new CodeInstruction(OpCodes.Ldc_I4_1, (object)null);
								yield return new CodeInstruction(OpCodes.Add, (object)null);
								yield return new CodeInstruction(OpCodes.Stfld, (object)AccessTools.Field(typeof(Host), "UpdatesPlacedInDelayBuffer"));
								yield return new CodeInstruction(OpCodes.Ldloc_S, local_i);
								yield return new CodeInstruction(OpCodes.Ldc_I4_1, (object)null);
								yield return new CodeInstruction(OpCodes.Add, (object)null);
								yield return new CodeInstruction(OpCodes.Stloc_S, local_i);
								yield return CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Ldloc_S, local_i), new Label[1] { last_br.Value });
								yield return new CodeInstruction(OpCodes.Ldloc_S, local_m);
								yield return new CodeInstruction(OpCodes.Blt_S, (object)label);
							}
							else
							{
								instructionsSkipped[instructionsSkipped.Count - 7].labels.Add((Label)instructionsSkipped[instructionsSkipped.Count - 1].operand);
								for (int j = instructionsSkipped.Count - 7; j < instructionsSkipped.Count; j++)
								{
									yield return instructionsSkipped[j];
								}
							}
							continue;
						}
						foreach (CodeInstruction item in instructionsSkipped)
						{
							yield return item;
						}
						yield break;
					}
					foreach (CodeInstruction item2 in instructionsSkipped)
					{
						yield return item2;
					}
				}
				else
				{
					yield return instruction;
					blabel = null;
				}
			}
			enumerator.Dispose();
		}
	}
	[HarmonyPatch(typeof(Host))]
	[HarmonyPatch("Update")]
	public class HostPatch_Update
	{
		public static int GetCount()
		{
			return HostPatch.InputBuffer.Count;
		}

		public static MultiInputPacket Dequeue()
		{
			return HostPatch.InputBuffer.Dequeue();
		}

		public static int GetTargetDelayBufferSize(MultiInputPacket packet, int currentTargetDelayBufferSize)
		{
			if (HostPatch.GetMaxSeqNumber(packet) % 32 == 0)
			{
				int maxPreviousTargetDelayBufferSize = HostPatch.GetMaxPreviousTargetDelayBufferSize();
				if (maxPreviousTargetDelayBufferSize > 0)
				{
					return maxPreviousTargetDelayBufferSize;
				}
			}
			return currentTargetDelayBufferSize;
		}

		public static void OverrideInputWithNetworkInput(MultiInputPacket packet)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			PlayerHandler val = PlayerHandler.Get();
			List<Player> list = val.PlayerList();
			for (int i = 0; i < list.Count; i++)
			{
				if (packet.inputPackets.TryGetValue(list[i].Id, out var value))
				{
					list[i].OverrideInputWithNetworkInput(value);
				}
			}
			HostPatch.previousInputPacket = packet;
		}

		public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			Plugin.Log.LogInfo((object)"Patching Host.Update");
			FieldInfo inputBufferFieldInfo = AccessTools.Field(typeof(Host), "InputBuffer");
			MethodInfo getCountMethodInfo = AccessTools.Method(inputBufferFieldInfo.FieldType, "get_Count", (Type[])null, (Type[])null);
			MethodInfo dequeueMethodInfo = AccessTools.Method(inputBufferFieldInfo.FieldType, "Dequeue", (Type[])null, (Type[])null);
			IEnumerator<CodeInstruction> enumerator = instructions.GetEnumerator();
			LocalBuilder mipl = generator.DeclareLocal(typeof(MultiInputPacket));
			bool foundInputBuffer = false;
			Label? label = default(Label?);
			while (enumerator.MoveNext())
			{
				CodeInstruction instruction5 = enumerator.Current;
				if (CodeInstructionExtensions.LoadsField(instruction5, inputBufferFieldInfo, false))
				{
					Plugin.Log.LogInfo((object)"Found InputBuffer field load instruction");
					foundInputBuffer = true;
					if (!enumerator.MoveNext())
					{
						Plugin.Log.LogError((object)"Expected to find next instruction after InputBuffer field load instruction");
						yield return instruction5;
						continue;
					}
					instruction5 = enumerator.Current;
					if (CodeInstructionExtensions.Calls(instruction5, getCountMethodInfo))
					{
						Plugin.Log.LogInfo((object)"Patching InputBuffer.getCount");
						yield return new CodeInstruction(OpCodes.Pop, (object)null);
						yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(HostPatch_Update), "GetCount", (Type[])null, (Type[])null));
						continue;
					}
					if (CodeInstructionExtensions.Calls(instruction5, dequeueMethodInfo))
					{
						Plugin.Log.LogInfo((object)"Patching InputBuffer.Dequeue");
						yield return new CodeInstruction(OpCodes.Pop, (object)null);
						yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(HostPatch_Update), "Dequeue", (Type[])null, (Type[])null));
						if (!enumerator.MoveNext() && enumerator.Current.opcode == OpCodes.Stloc_S)
						{
							Plugin.Log.LogError((object)"Expected a store local instruction.");
							break;
						}
						yield return new CodeInstruction(OpCodes.Stloc, (object)mipl);
						while (enumerator.MoveNext())
						{
							instruction5 = enumerator.Current;
							if (!(instruction5.opcode == OpCodes.Ldarg_0))
							{
								continue;
							}
							if (!enumerator.MoveNext())
							{
								Plugin.Log.LogError((object)"Expected to find next instruction after Ldarg_0");
								yield return instruction5;
								continue;
							}
							instruction5 = enumerator.Current;
							if (!CodeInstructionExtensions.LoadsField(instruction5, AccessTools.Field(typeof(Host), "AdaptiveInputDelayBuffer"), false))
							{
								continue;
							}
							Plugin.Log.LogInfo((object)"Found AdaptiveInputDelayBuffer check");
							yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
							yield return instruction5;
							if (!enumerator.MoveNext())
							{
								Plugin.Log.LogError((object)"Invalid input instruction stream.");
								continue;
							}
							instruction5 = enumerator.Current;
							yield return instruction5;
							if (!CodeInstructionExtensions.Branches(instruction5, ref label))
							{
								Plugin.Log.LogError((object)"Assumption about branch after AdaptiveInputDelayBuffer was incorrect.");
								continue;
							}
							while (enumerator.MoveNext())
							{
								instruction5 = enumerator.Current;
								if (CodeInstructionExtensions.StoresField(instruction5, AccessTools.Field(typeof(Host), "targetDelayBufferSize")))
								{
									break;
								}
							}
							yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
							yield return new CodeInstruction(OpCodes.Ldloc, (object)mipl);
							yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
							yield return new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Host), "targetDelayBufferSize"));
							yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(HostPatch_Update), "GetTargetDelayBufferSize", (Type[])null, (Type[])null));
							yield return new CodeInstruction(OpCodes.Stfld, (object)AccessTools.Field(typeof(Host), "targetDelayBufferSize"));
							break;
						}
						continue;
					}
					Plugin.Log.LogError((object)"Failed to patch InputBuffer reference out.");
				}
				if (foundInputBuffer && CodeInstructionExtensions.Calls(instruction5, AccessTools.Method(typeof(PlayerHandler), "Get", (Type[])null, (Type[])null)))
				{
					Plugin.Log.LogInfo((object)"Patching PlayerHandler.Get calls");
					while (enumerator.MoveNext() && !CodeInstructionExtensions.StoresField(enumerator.Current, AccessTools.Field(typeof(Host), "previousInputQuad")))
					{
					}
					if (enumerator.Current == null)
					{
						Plugin.Log.LogError((object)"Failed to find previousInputQuad store");
						break;
					}
					yield return new CodeInstruction(OpCodes.Ldloc, (object)mipl);
					yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(HostPatch_Update), "OverrideInputWithNetworkInput", (Type[])null, (Type[])null));
				}
				else
				{
					yield return instruction5;
				}
			}
		}
	}
	public struct MultiInputPacket
	{
		public Dictionary<int, InputPacket> inputPackets;

		public MultiInputPacket()
		{
			inputPackets = new Dictionary<int, InputPacket>();
		}

		public void Log()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Log.LogInfo((object)$"MultiInputPacket: {inputPackets.Count} input packets");
			foreach (KeyValuePair<int, InputPacket> inputPacket in inputPackets)
			{
				Plugin.Log.LogInfo((object)$"Player {inputPacket.Key}:");
				Plugin.Log.LogInfo((object)$"seqNumber: {inputPacket.Value.seqNumber}");
				Plugin.Log.LogInfo((object)$"joystickAngle: {inputPacket.Value.joystickAngle}");
				Plugin.Log.LogInfo((object)$"jump: {inputPacket.Value.jump}");
				Plugin.Log.LogInfo((object)$"ab1: {inputPacket.Value.ab1}");
				Plugin.Log.LogInfo((object)$"ab2: {inputPacket.Value.ab2}");
				Plugin.Log.LogInfo((object)$"ab3: {inputPacket.Value.ab3}");
				Plugin.Log.LogInfo((object)$"start: {inputPacket.Value.start}");
				Plugin.Log.LogInfo((object)$"select: {inputPacket.Value.select}");
				Plugin.Log.LogInfo((object)$"w: {inputPacket.Value.w}");
				Plugin.Log.LogInfo((object)$"a: {inputPacket.Value.a}");
				Plugin.Log.LogInfo((object)$"s: {inputPacket.Value.s}");
				Plugin.Log.LogInfo((object)$"d: {inputPacket.Value.d}");
				Plugin.Log.LogInfo((object)$"targetDelayBufferSize: {inputPacket.Value.targetDelayBufferSize}");
			}
		}
	}
	public struct MultiStartRequestPacket
	{
		public ushort seqNum;

		public uint seed;

		public byte nrOfPlayers;

		public byte nrOfAbilites;

		public byte currentLevel;

		public byte frameBufferSize;

		public byte isDemoMask;

		public ulong[] p_ids;

		public byte[] p_colors;

		public byte[] p_teams;

		public byte[] p_ability1s;

		public byte[] p_ability2s;

		public byte[] p_ability3s;

		public void Initialize(int count)
		{
			p_ids = new ulong[count];
			p_colors = new byte[count];
			p_teams = new byte[count];
			p_ability1s = new byte[count];
			p_ability2s = new byte[count];
			p_ability3s = new byte[count];
		}

		public override string ToString()
		{
			return string.Format("seqNum: {0}, seed: {1}, nrOfPlayers: {2}, nrOfAbilites: {3}, currentLevel: {4}, frameBufferSize: {5}, isDemoMask: {6}, p_ids: {7}, p_colors: {8}, p_teams: {9}, p_ability1s: {10}, p_ability2s: {11}, p_ability3s: {12}", seqNum, seed, nrOfPlayers, nrOfAbilites, currentLevel, frameBufferSize, isDemoMask, string.Join(", ", p_ids), string.Join(", ", p_colors), string.Join(", ", p_teams), string.Join(", ", p_ability1s), string.Join(", ", p_ability2s), string.Join(", ", p_ability3s));
		}
	}
	public static class NetworkToolsExtensions
	{
		public static MultiStartRequestPacket ReadMultiStartRequest(byte[] data, ref byte[] uintConversionHelperArray, ref byte[] ulongConversionHelperArray, ref byte[] ushortConversionHelperArray)
		{
			Plugin.Log.LogInfo((object)$"Decoding MultiStartRequestPacket, size of array: {data.Length}");
			MultiStartRequestPacket result = default(MultiStartRequestPacket);
			int num = 0;
			ushortConversionHelperArray[0] = data[num++];
			ushortConversionHelperArray[1] = data[num++];
			result.seqNum = NetworkTools.SwapBytesIfLittleEndian(BitConverter.ToUInt16(ushortConversionHelperArray, 0));
			Plugin.Log.LogInfo((object)$"Decoded seqNum: {result.seqNum} (byte: {num})");
			uintConversionHelperArray[0] = data[num++];
			uintConversionHelperArray[1] = data[num++];
			uintConversionHelperArray[2] = data[num++];
			uintConversionHelperArray[3] = data[num++];
			result.seed = NetworkTools.SwapBytesIfLittleEndian(BitConverter.ToUInt32(uintConversionHelperArray, 0));
			Plugin.Log.LogInfo((object)$"Decoded seed: {result.seed} (byte: {num})");
			result.nrOfPlayers = data[num++];
			result.nrOfAbilites = data[num++];
			result.currentLevel = data[num++];
			result.frameBufferSize = data[num++];
			result.isDemoMask = data[num++];
			Plugin.Log.LogInfo((object)$"Decoded nrOfPlayers: {result.nrOfPlayers}, nrOfAbilities: {result.nrOfAbilites}, currentLevel: {result.currentLevel}, frameBufferSize: {result.frameBufferSize}, isDemoMask: {result.isDemoMask} (byte: {num})");
			result.Initialize(result.nrOfPlayers);
			for (int i = 0; i < result.nrOfPlayers; i++)
			{
				ulongConversionHelperArray[0] = data[num++];
				ulongConversionHelperArray[1] = data[num++];
				ulongConversionHelperArray[2] = data[num++];
				ulongConversionHelperArray[3] = data[num++];
				ulongConversionHelperArray[4] = data[num++];
				ulongConversionHelperArray[5] = data[num++];
				ulongConversionHelperArray[6] = data[num++];
				ulongConversionHelperArray[7] = data[num++];
				result.p_ids[i] = NetworkTools.SwapBytesIfLittleEndian(BitConverter.ToUInt64(ulongConversionHelperArray, 0));
				Plugin.Log.LogInfo((object)$"Decoded p_ids[{i}]: {result.p_ids[i]} (byte: {num})");
			}
			for (int j = 0; j < result.nrOfPlayers; j++)
			{
				result.p_colors[j] = data[num++];
				Plugin.Log.LogInfo((object)$"Decoded p_colors[{j}]: {result.p_colors[j]} (byte: {num})");
			}
			for (int k = 0; k < result.nrOfPlayers; k++)
			{
				result.p_teams[k] = data[num++];
				Plugin.Log.LogInfo((object)$"Decoded p_teams[{k}]: {result.p_teams[k]} (byte: {num})");
			}
			for (int l = 0; l < result.nrOfPlayers; l++)
			{
				result.p_ability1s[l] = data[num++];
				Plugin.Log.LogInfo((object)$"Decoded p_ability1s[{l}]: {result.p_ability1s[l]} (byte: {num})");
			}
			for (int m = 0; m < result.nrOfPlayers; m++)
			{
				result.p_ability2s[m] = data[num++];
				Plugin.Log.LogInfo((object)$"Decoded p_ability2s[{m}]: {result.p_ability2s[m]} (byte: {num})");
			}
			for (int n = 0; n < result.nrOfPlayers; n++)
			{
				result.p_ability3s[n] = data[num++];
				Plugin.Log.LogInfo((object)$"Decoded p_ability3s[{n}]: {result.p_ability3s[n]} (byte: {num})");
			}
			return result;
		}

		public static void EncodeMultiStartRequest(ref byte[] data, MultiStartRequestPacket p)
		{
			Plugin.Log.LogInfo((object)$"Encoding MultiStartRequestPacket, size of array: {data.Length}");
			int num = 0;
			Plugin.Log.LogInfo((object)$"Encoding seqNum: {p.seqNum} (byte: {num})");
			p.seqNum = NetworkTools.SwapBytesIfLittleEndian(p.seqNum);
			byte[] bytes = BitConverter.GetBytes(p.seqNum);
			data[num++] = bytes[0];
			data[num++] = bytes[1];
			Plugin.Log.LogInfo((object)$"Encoding seed: {p.seed} (byte: {num})");
			p.seed = NetworkTools.SwapBytesIfLittleEndian(p.seed);
			bytes = BitConverter.GetBytes(p.seed);
			data[num++] = bytes[0];
			data[num++] = bytes[1];
			data[num++] = bytes[2];
			data[num++] = bytes[3];
			data[num++] = p.nrOfPlayers;
			data[num++] = p.nrOfAbilites;
			data[num++] = p.currentLevel;
			data[num++] = p.frameBufferSize;
			data[num++] = p.isDemoMask;
			Plugin.Log.LogInfo((object)$"Encoded nrOfPlayers: {p.nrOfPlayers}, nrOfAbilities: {p.nrOfAbilites}, currentLevel: {p.currentLevel}, frameBufferSize: {p.frameBufferSize}, isDemoMask: {p.isDemoMask} (byte: {num})");
			for (int i = 0; i < p.nrOfPlayers; i++)
			{
				Plugin.Log.LogInfo((object)$"Encoding p_ids[{i}]: {p.p_ids[i]} (byte: {num})");
				ulong value = NetworkTools.SwapBytesIfLittleEndian(p.p_ids[i]);
				bytes = BitConverter.GetBytes(value);
				data[num++] = bytes[0];
				data[num++] = bytes[1];
				data[num++] = bytes[2];
				data[num++] = bytes[3];
				data[num++] = bytes[4];
				data[num++] = bytes[5];
				data[num++] = bytes[6];
				data[num++] = bytes[7];
			}
			for (int j = 0; j < p.nrOfPlayers; j++)
			{
				data[num++] = p.p_colors[j];
				Plugin.Log.LogInfo((object)$"Encoded p_colors[{j}]: {p.p_colors[j]} (byte: {num})");
			}
			for (int k = 0; k < p.nrOfPlayers; k++)
			{
				data[num++] = p.p_teams[k];
				Plugin.Log.LogInfo((object)$"Encoded p_teams[{k}]: {p.p_teams[k]} (byte: {num})");
			}
			for (int l = 0; l < p.nrOfPlayers; l++)
			{
				data[num++] = p.p_ability1s[l];
				Plugin.Log.LogInfo((object)$"Encoded p_ability1s[{l}]: {p.p_ability1s[l]} (byte: {num})");
			}
			for (int m = 0; m < p.nrOfPlayers; m++)
			{
				data[num++] = p.p_ability2s[m];
				Plugin.Log.LogInfo((object)$"Encoded p_ability2s[{m}]: {p.p_ability2s[m]} (byte: {num})");
			}
			for (int n = 0; n < p.nrOfPlayers; n++)
			{
				data[num++] = p.p_ability3s[n];
				Plugin.Log.LogInfo((object)$"Encoded p_ability3s[{n}]: {p.p_ability3s[n]} (byte: {num})");
			}
		}

		public static int GetMultiStartRequestSize(MultiStartRequestPacket startParameters)
		{
			return 11 + startParameters.nrOfPlayers * 13;
		}
	}
	[HarmonyPatch(typeof(NetworkTools))]
	[HarmonyPatch("ReadLobbyReadyPacket")]
	public static class NetworkTools_ReadLobbyReadyPacket
	{
		private static void Postfix(ref LobbyReadyPacket __result)
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			Debug.Log((object)"ReadLobbyReadyPacket");
			Debug.Log((object)__result.steamId);
			Debug.Log((object)__result.ability1);
			Debug.Log((object)__result.ability2);
			Debug.Log((object)__result.ability3);
			Debug.Log((object)__result.color);
			Debug.Log((object)__result.team);
			Debug.Log((object)__result.ownsFullGame);
			Debug.Log((object)__result.usesKeyboardAndMouse);
			Debug.Log((object)"Connected Players");
			foreach (SteamConnection connectedPlayer in SteamManager.instance.connectedPlayers)
			{
				Debug.Log((object)connectedPlayer.id);
			}
		}
	}
	[BepInPlugin("MoreMultiPlayer", "MoreMultiPlayer", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private Harmony harmony;

		private static IEnumerable<CodeInstruction> SteamManagerCreateFriendLobbyPatch(IEnumerable<CodeInstruction> instructions)
		{
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.LoadsConstant(instruction, 4L))
				{
					Log.LogMessage((object)$"Found create lobby instruction to patch from 4 to {Constants.MAX_PLAYERS}");
					yield return new CodeInstruction(OpCodes.Ldc_I4, (object)Constants.MAX_PLAYERS);
				}
				else
				{
					yield return instruction;
				}
			}
		}

		public static IEnumerable<CodeInstruction> PatchFieldLoad(FieldInfo fromA, FieldInfo fromB, FieldInfo toA, FieldInfo toB, IEnumerable<CodeInstruction> instructions)
		{
			bool patched = false;
			IEnumerator<CodeInstruction> enumerator = instructions.GetEnumerator();
			while (enumerator.MoveNext())
			{
				CodeInstruction instruction = enumerator.Current;
				if (CodeInstructionExtensions.LoadsField(instruction, fromA, true))
				{
					if (!enumerator.MoveNext())
					{
						Log.LogError((object)$"Expected to find next instruction after {fromA} load instruction");
						yield return instruction;
					}
					CodeInstruction nextInstruction = enumerator.Current;
					if (!CodeInstructionExtensions.LoadsField(nextInstruction, fromB, false))
					{
						Log.LogInfo((object)$"Candidate patch instruction is not loading {fromB} field was: {nextInstruction.opcode}:{nextInstruction.operand}");
						yield return instruction;
						yield return nextInstruction;
					}
					else
					{
						Log.LogInfo((object)$"Found {fromA} field load instruction to patch");
						Log.LogInfo((object)$"Found {fromB} field load instruction to patch");
						yield return new CodeInstruction(instruction.opcode, (object)toA);
						yield return new CodeInstruction(nextInstruction.opcode, (object)toB);
						patched = true;
					}
				}
				else
				{
					yield return instruction;
				}
			}
			if (!patched)
			{
				Log.LogError((object)"Failed to patch GameSessionHandler.LoadNextLevelScene");
			}
		}

		private void Test()
		{
			SteamManagerExtended.startParameters = default(MultiStartRequestPacket);
			SteamManagerExtended.startParameters.seqNum = 5;
			SteamManagerExtended.startParameters.nrOfPlayers = 2;
			SteamManagerExtended.startParameters.nrOfAbilites = (byte)Settings.Get().NumberOfAbilities;
			SteamManagerExtended.startParameters.currentLevel = GameSession.CurrentLevel();
			SteamManagerExtended.startParameters.seed = (uint)Environment.TickCount;
			SteamManagerExtended.startParameters.Initialize(1);
			SteamManagerExtended.startParameters.p_ids[0] = 10uL;
			SteamManagerExtended.startParameters.p_teams[0] = 1;
			SteamManagerExtended.startParameters.p_colors[0] = 2;
			SteamManagerExtended.startParameters.p_ability1s[0] = 3;
			SteamManagerExtended.startParameters.p_ability2s[0] = 4;
			SteamManagerExtended.startParameters.p_ability3s[0] = 5;
			for (int i = 1; i < 2; i++)
			{
				SteamManagerExtended.startParameters.p_ids[i] = (byte)i;
				SteamManagerExtended.startParameters.p_teams[i] = (byte)i;
				SteamManagerExtended.startParameters.p_colors[i] = (byte)i;
				SteamManagerExtended.startParameters.p_ability1s[i] = 4;
				SteamManagerExtended.startParameters.p_ability2s[i] = 24;
				SteamManagerExtended.startParameters.p_ability3s[i] = 56;
			}
			byte b = (byte)(SteamManager.instance.dlc.HasDLC() ? 1u : 0u);
			for (int j = 0; j < 1; j++)
			{
				bool flag = true;
				b = (byte)(b | (1 << j + 1));
			}
			SteamManagerExtended.startParameters.isDemoMask = b;
			byte[] data = new byte[NetworkToolsExtensions.GetMultiStartRequestSize(SteamManagerExtended.startParameters)];
			NetworkToolsExtensions.EncodeMultiStartRequest(ref data, SteamManagerExtended.startParameters);
		}

		private void Awake()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"secret number 5");
			HarmonyFileLog.Enabled = true;
			Log.LogInfo((object)HarmonyFileLog.FileWriterPath);
			Constants.MAX_PLAYERS = 8;
			Host.recordReplay = false;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Disabled replay recording");
			harmony = new Harmony("MoreMultiPlayer");
			harmony.PatchAll();
			MethodInfo method = typeof(SteamManager).GetMethod("CreateFriendLobby", BindingFlags.Instance | BindingFlags.Public);
			if (method == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Failed to find SteamManager::CreateFriendLobby!");
				return;
			}
			AsyncStateMachineAttribute customAttribute = method.GetCustomAttribute<AsyncStateMachineAttribute>();
			MethodInfo method2 = customAttribute.StateMachineType.GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.NonPublic);
			MethodInfo method3 = typeof(Plugin).GetMethod("SteamManagerCreateFriendLobbyPatch", BindingFlags.Static | BindingFlags.NonPublic);
			PatchProcessor val = harmony.CreateProcessor((MethodBase)method2);
			val.AddTranspiler(method3);
			val.Patch();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin MoreMultiPlayer is loaded!");
		}

		private void OnDestroy()
		{
			harmony.UnpatchSelf();
		}
	}
	[HarmonyPatch(typeof(printText))]
	[HarmonyPatch("Awake")]
	public static class YourPatchClass
	{
		public static void Postfix()
		{
			Plugin.Log.LogInfo((object)("Found version " + Constants.version));
			Constants.version += "-mpmodded";
			Plugin.Log.LogInfo((object)("Patched to version " + Constants.version));
		}
	}
	internal class SteamManagerExtended
	{
		public static MultiStartRequestPacket startParameters;
	}
	[HarmonyPatch(typeof(SteamManager))]
	[HarmonyPatch("HostGame")]
	internal static class SteamManagerPatch_HostGame
	{
		private static FieldRef<SteamManager, ushort> nextStartGameSeqAccess = AccessTools.FieldRefAccess<SteamManager, ushort>("nextStartGameSeq");

		public static bool Prefix(SteamManager __instance, PlayerInit hostPlayer)
		{
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Log.LogInfo((object)"Running custom HostGame patch");
			((Lobby)(ref __instance.currentLobby)).SetData("LFM", "0");
			((Lobby)(ref __instance.currentLobby)).SetFriendsOnly();
			((Lobby)(ref __instance.currentLobby)).SetJoinable(false);
			SteamManagerExtended.startParameters = default(MultiStartRequestPacket);
			SteamManagerExtended.startParameters.seqNum = nextStartGameSeqAccess.Invoke(__instance)++;
			SteamManagerExtended.startParameters.nrOfPlayers = (byte)(__instance.connectedPlayers.Count + 1);
			SteamManagerExtended.startParameters.nrOfAbilites = (byte)Settings.Get().NumberOfAbilities;
			SteamManagerExtended.startParameters.currentLevel = GameSession.CurrentLevel();
			SteamManagerExtended.startParameters.seed = (uint)Environment.TickCount;
			SteamManagerExtended.startParameters.Initialize(__instance.connectedPlayers.Count + 1);
			ManualLogSource log = Plugin.Log;
			SteamId steamId = SteamClient.SteamId;
			log.LogInfo((object)("My SteamID: " + ((object)(SteamId)(ref steamId)).ToString()));
			SteamManagerExtended.startParameters.p_ids[0] = SteamId.op_Implicit(SteamClient.SteamId);
			SteamManagerExtended.startParameters.p_teams[0] = (byte)hostPlayer.team;
			SteamManagerExtended.startParameters.p_colors[0] = (byte)hostPlayer.color;
			SteamManagerExtended.startParameters.p_ability1s[0] = (byte)hostPlayer.ability0;
			SteamManagerExtended.startParameters.p_ability2s[0] = (byte)hostPlayer.ability1;
			SteamManagerExtended.startParameters.p_ability3s[0] = (byte)hostPlayer.ability2;
			for (int i = 1; i < SteamManagerExtended.startParameters.nrOfPlayers; i++)
			{
				Plugin.Log.LogInfo((object)$"{i} <? {__instance.connectedPlayers.Count}");
				SteamManagerExtended.startParameters.p_ids[i] = SteamId.op_Implicit(__instance.connectedPlayers[i - 1].id);
				SteamManagerExtended.startParameters.p_teams[i] = __instance.connectedPlayers[i - 1].lobby_team;
				SteamManagerExtended.startParameters.p_colors[i] = (byte)__instance.connectedPlayers[i - 1].lobby_color;
				SteamManagerExtended.startParameters.p_ability1s[i] = __instance.connectedPlayers[i - 1].lobby_ability1;
				SteamManagerExtended.startParameters.p_ability2s[i] = __instance.connectedPlayers[i - 1].lobby_ability2;
				SteamManagerExtended.startParameters.p_ability3s[i] = __instance.connectedPlayers[i - 1].lobby_ability3;
			}
			byte b = (byte)(SteamManager.instance.dlc.HasDLC() ? 1u : 0u);
			for (int j = 0; j < __instance.connectedPlayers.Count; j++)
			{
				if (__instance.connectedPlayers[j].ownsFullGame)
				{
					b = (byte)(b | (1 << j + 1));
				}
			}
			SteamManagerExtended.startParameters.isDemoMask = b;
			byte[] data = new byte[NetworkToolsExtensions.GetMultiStartRequestSize(SteamManagerExtended.startParameters)];
			Plugin.Log.LogInfo((object)SteamManagerExtended.startParameters.ToString());
			NetworkToolsExtensions.EncodeMultiStartRequest(ref data, SteamManagerExtended.startParameters);
			for (int k = 0; k < __instance.connectedPlayers.Count; k++)
			{
				((Connection)(ref ((ConnectionManager)__instance.connectedPlayers[k]).Connection)).SendMessage(data, (SendType)8);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(SteamManager))]
	[HarmonyPatch("ForceLoadNextLevel")]
	internal static class SteamManagerPatch_ForceLoadNextLevel
	{
		[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPatch(typeof(SteamManager), "ChangePlayerAbilites")]
		public static void ChangePlayerAbilities(Player player, byte ability1, byte ability2, byte ability3, int nrOfAbilities, NamedSpriteList abilityIcons)
		{
			throw new NotImplementedException("It's a stub");
		}

		public static bool Prefix()
		{
			Plugin.Log.LogInfo((object)"Running custom ForceLoadNextLevel patch");
			SteamManager.networkClientHandle.DeInit();
			MultiStartRequestPacket startParameters = SteamManagerExtended.startParameters;
			List<Player> list = PlayerHandler.Get().PlayerList();
			if (startParameters.nrOfPlayers <= 1)
			{
				GameSessionHandler.LeaveGame(true, false);
				return false;
			}
			int num;
			for (num = list.Count - 1; num >= 0; num--)
			{
				if (!list[num].IsLocalPlayer && !SteamManager.instance.connectedPlayers.Any((SteamConnection player) => SteamId.op_Implicit(player.id) == SteamId.op_Implicit(list[num].steamId)))
				{
					list.RemoveAt(num);
					Debug.Log((object)"dropping player because they were disconnected");
				}
			}
			for (int i = 0; i < list.Count; i++)
			{
				ChangePlayerAbilities(list[i], startParameters.p_ability1s[i], startParameters.p_ability2s[i], startParameters.p_ability3s[i], startParameters.nrOfAbilites, SteamManager.instance.abilityIcons);
			}
			GameSession.SetCurrentLevel(startParameters.currentLevel);
			if (!GameSessionHandler.GameIsPaused)
			{
				CharacterStatsList.ForceNextLevelImmediately();
			}
			else
			{
				CharacterStatsList.ForceNextLevelLoad();
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(SteamManager))]
	[HarmonyPatch("InitNetworkClient")]
	internal static class SteamManagerPatch_InitNetworkClient
	{
		private static bool Prefix(SteamManager __instance)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			Plugin.Log.LogInfo((object)"Running custom InitNetworkClient patch");
			int num = Array.IndexOf(SteamManagerExtended.startParameters.p_ids, SteamClient.SteamId.Value) + 1;
			List<Client> list = new List<Client>();
			foreach (SteamConnection connectedPlayer in __instance.connectedPlayers)
			{
				ulong value = connectedPlayer.id.Value;
				int num2 = Array.IndexOf(SteamManagerExtended.startParameters.p_ids, value) + 1;
				list.Add(new Client(num2, connectedPlayer));
			}
			__instance.networkClient.Init(list, num, SteamManagerExtended.startParameters.currentLevel, __instance.startFrameBuffer, __instance.checkForDesyncs);
			SteamManager.networkClientHandle = __instance.networkClient;
			return false;
		}
	}
	[HarmonyPatch(typeof(SteamManager))]
	[HarmonyPatch("HostNextLevel")]
	internal static class SteamManagerPatch_HostNextLevel
	{
		private static bool Prefix(SteamManager __instance, Player hostPlayer, NamedSpriteList abilityIcons)
		{
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Log.LogInfo((object)"Running custom HostNextLevel patch");
			GameSession.CurrentLevel();
			SteamManagerExtended.startParameters.frameBufferSize = (byte)Host.CurrentDelayBufferSize;
			SteamManagerExtended.startParameters.seed = (uint)Environment.TickCount;
			SteamManagerExtended.startParameters.nrOfPlayers = (byte)(__instance.connectedPlayers.Count + 1);
			SteamManagerExtended.startParameters.currentLevel = GameSession.CurrentLevel();
			SteamManagerExtended.startParameters.p_ability1s[0] = (byte)abilityIcons.IndexOf(((Object)hostPlayer.Abilities[0]).name);
			if (Settings.Get().NumberOfAbilities > 1)
			{
				SteamManagerExtended.startParameters.p_ability2s[0] = (byte)abilityIcons.IndexOf(((Object)hostPlayer.Abilities[1]).name);
			}
			if (Settings.Get().NumberOfAbilities > 2)
			{
				SteamManagerExtended.startParameters.p_ability3s[0] = (byte)abilityIcons.IndexOf(((Object)hostPlayer.Abilities[2]).name);
			}
			for (int i = 0; i < __instance.connectedPlayers.Count; i++)
			{
				SteamManagerExtended.startParameters.p_ability1s[i + 1] = __instance.connectedPlayers[i].lobby_ability1;
				SteamManagerExtended.startParameters.p_ability2s[i + 1] = __instance.connectedPlayers[i].lobby_ability2;
				SteamManagerExtended.startParameters.p_ability3s[i + 1] = __instance.connectedPlayers[i].lobby_ability3;
			}
			byte[] data = new byte[NetworkToolsExtensions.GetMultiStartRequestSize(SteamManagerExtended.startParameters)];
			NetworkToolsExtensions.EncodeMultiStartRequest(ref data, SteamManagerExtended.startParameters);
			for (int j = 0; j < __instance.connectedPlayers.Count; j++)
			{
				((Connection)(ref ((ConnectionManager)__instance.connectedPlayers[j]).Connection)).SendMessage(data, (SendType)8);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(SteamSocket))]
	[HarmonyPatch("OnMessage")]
	public static class SteamSocketPatch_OnMessage
	{
		private static byte[] ulongConversionArray = new byte[8];

		private static byte[] uintConversionArray = new byte[4];

		private static byte[] ushortConversionArray = new byte[2];

		private static CodeInstruction Log(CodeInstruction i)
		{
			Plugin.Log.LogInfo((object)i);
			return i;
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			Plugin.Log.LogInfo((object)"Patching SteamSocket.OnMessage()");
			IEnumerator<CodeInstruction> enumerator = instructions.GetEnumerator();
			while (enumerator.MoveNext())
			{
				CodeInstruction instruction2 = enumerator.Current;
				if (CodeInstructionExtensions.Calls(instruction2, AccessTools.Method(typeof(Ack), "get_PacketTypeAsEnum", (Type[])null, (Type[])null)))
				{
					yield return instruction2;
					if (!enumerator.MoveNext())
					{
						Plugin.Log.LogError((object)"Expected to find next instruction after Ack.get_PacketTypeAsEnum() call");
						break;
					}
					instruction2 = enumerator.Current;
					if (CodeInstructionExtensions.LoadsConstant(instruction2, 5L))
					{
						yield return Log(new CodeInstruction(OpCodes.Ldc_I4, (object)254));
					}
					else if (CodeInstructionExtensions.LoadsConstant(instruction2, 6L))
					{
						yield return new CodeInstruction(OpCodes.Ldc_I4, (object)255);
					}
					else
					{
						yield return instruction2;
					}
				}
				else
				{
					yield return instruction2;
				}
			}
		}

		private static bool Prefix(SteamSocket __instance, Connection connection, NetIdentity identity, IntPtr data, int size, long messageNum, long recvTime, int channel)
		{
			//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)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			if (size >= 24 && size != 67 && size != 83)
			{
				SteamId steamId = ((NetIdentity)(ref identity)).SteamId;
				if (!((SteamId)(ref steamId)).IsValid)
				{
					Plugin.Log.LogWarning((object)"got message from invalid steamId");
					return false;
				}
				SteamId steamId2 = ((NetIdentity)(ref identity)).SteamId;
				Friend val = new Friend(steamId2);
				if (!((Friend)(ref val)).IsIn(((Lobby)(ref SteamManager.instance.currentLobby)).Id))
				{
					ManualLogSource log = Plugin.Log;
					steamId = ((NetIdentity)(ref identity)).SteamId;
					log.LogWarning((object)("Ignored a msg from " + ((object)(SteamId)(ref steamId)).ToString()));
					return false;
				}
				byte[] array = new byte[size];
				Marshal.Copy(data, array, 0, size);
				if (((Lobby)(ref SteamManager.instance.currentLobby)).IsOwnedBy(((NetIdentity)(ref identity)).SteamId))
				{
					SteamManagerExtended.startParameters = NetworkToolsExtensions.ReadMultiStartRequest(array, ref uintConversionArray, ref ulongConversionArray, ref ushortConversionArray);
					if (GameSession.inMenus)
					{
						CharacterSelectHandler_online.ForceStartGame((PlayerColors)null);
					}
					else
					{
						SteamManager.ForceLoadNextLevel();
					}
				}
				return false;
			}
			return true;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "MoreMultiPlayer";

		public const string PLUGIN_NAME = "MoreMultiPlayer";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}