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.Configuration;
using BepInEx.Logging;
using HarmonyLib;
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 = "")]
[assembly: AssemblyCompany("MorePlayers")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Allows 8 players to join a lobby!")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+d0ca91154202c4b9c82b8d5e1419d1db5f8945fd")]
[assembly: AssemblyProduct("MorePlayers")]
[assembly: AssemblyTitle("MorePlayers")]
[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 MorePlayers
{
[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);
Main.Log.LogInfo((object)$"SteamID: {SteamClient.SteamId}");
for (int i = 0; i < startParameters.nrOfPlayers; i++)
{
Main.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));
Main.Log.LogInfo((object)("SteamIdIndex: " + num));
if (num != -1)
{
val2 = list[num];
}
}
if (val2 == null)
{
Main.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)
{
Main.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 Main.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();
Main.Log.LogInfo((object)$"Spawning {list.Count} players:");
foreach (Player item in list)
{
Main.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)
{
Main.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 Main.PatchFieldLoad(fromA, fromB, toA, toB, instructions);
}
}
[HarmonyPatch(typeof(Host))]
[HarmonyPatch("ReInit")]
public class HostPatch_ReInit
{
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
Main.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 Main.PatchFieldLoad(fromA, fromB, toA, toB, instructions);
}
}
[HarmonyPatch(typeof(Host))]
[HarmonyPatch("Init")]
public class HostPatch_Init
{
public static void Prefix()
{
Main.Log.LogInfo((object)"Host::Init::Prefix");
HostPatch.previousInputPacket = new MultiInputPacket();
}
}
[HarmonyPatch(typeof(Host))]
[HarmonyPatch("ProcessNetworkPackets")]
public class HostPatch_ProcessNetworkPackets
{
private static void AddDefaultPacket()
{
Main.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)
{
Main.Log.LogInfo((object)message);
}
[HarmonyDebug]
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
Main.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())
{
Main.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)))
{
Main.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))
{
Main.Log.LogInfo((object)"Found End of loop");
foundEnd = true;
break;
}
}
if (foundEnd)
{
if (!last_br.HasValue)
{
Main.Log.LogError((object)"What this shouldn't be null?!");
}
if (instructionsSkipped.Any((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, delayBufferSizeFieldInfo, false)))
{
Main.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;
Main.Log.LogInfo((object)$"Local_i: {local_i}");
Main.Log.LogInfo((object)$"Local_m: {local_m}");
Main.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)
{
Main.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))
{
Main.Log.LogInfo((object)"Found InputBuffer field load instruction");
foundInputBuffer = true;
if (!enumerator.MoveNext())
{
Main.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))
{
Main.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))
{
Main.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)
{
Main.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())
{
Main.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;
}
Main.Log.LogInfo((object)"Found AdaptiveInputDelayBuffer check");
yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
yield return instruction5;
if (!enumerator.MoveNext())
{
Main.Log.LogError((object)"Invalid input instruction stream.");
continue;
}
instruction5 = enumerator.Current;
yield return instruction5;
if (!CodeInstructionExtensions.Branches(instruction5, ref label))
{
Main.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;
}
Main.Log.LogError((object)"Failed to patch InputBuffer reference out.");
}
if (foundInputBuffer && CodeInstructionExtensions.Calls(instruction5, AccessTools.Method(typeof(PlayerHandler), "Get", (Type[])null, (Type[])null)))
{
Main.Log.LogInfo((object)"Patching PlayerHandler.Get calls");
while (enumerator.MoveNext() && !CodeInstructionExtensions.StoresField(enumerator.Current, AccessTools.Field(typeof(Host), "previousInputQuad")))
{
}
if (enumerator.Current == null)
{
Main.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;
}
}
}
}
[BepInPlugin("com.MorePlayersTeam.MorePlayers", "MorePlayers", "1.0.0")]
public class Main : BaseUnityPlugin
{
internal static ManualLogSource Log;
private Harmony harmony;
private bool isVisible = true;
public static ConfigFile config;
public static ConfigEntry<int> maxPlayers;
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: {nextInstruction.opcode}:{nextInstruction.operand}");
yield return instruction;
yield return nextInstruction;
}
else
{
Log.LogInfo((object)$"Found {fromA} and {fromB} field load instructions 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 OnGUI()
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Expected O, but got Unknown
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Expected O, but got Unknown
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_0156: Unknown result type (might be due to invalid IL or missing references)
//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
//IL_01fe: 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)
int num = PlayerHandler.Get().NumberOfPlayers();
List<Player> list = PlayerHandler.Get().PlayerList();
GUI.color = new Color(0f, 0f, 0f, 0.5f);
GUIStyle val = new GUIStyle();
val.fontSize = 20;
val.normal.textColor = Color.white;
GUIStyle val2 = new GUIStyle();
val2.fontSize = 20;
val2.normal.textColor = Color.white;
if (GUI.Button(new Rect(350f, 60f, 100f, 30f), "Toggle Visibility"))
{
if (!isVisible)
{
isVisible = true;
}
else if (isVisible)
{
isVisible = false;
}
}
for (int i = 0; i < list.Count; i++)
{
if (!isVisible)
{
return;
}
string text = ((object)list[i].Color).ToString().Replace("Slime (UnityEngine.Material)", "");
string text2 = char.ToUpper(text[0]) + text.Substring(1);
float num2 = 130 + i * 25;
GUI.Label(new Rect(25f, num2, 300f, 30f), $"Player {text2} ({i + 1}): Kills: {list[i].Kills}, Deaths: {list[i].Deaths}, Cause of Death: {list[i].CauseOfDeath}", val);
}
if (isVisible)
{
GUI.Label(new Rect(25f, 100f, 300f, 30f), $"MoreBopl is running.. Currently: {num} players", val2);
GUI.DrawTexture(new Rect(0f, 100f, 650f, (float)(25 + list.Count * 25)), (Texture)(object)Texture2D.whiteTexture);
}
}
private void Awake()
{
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Log.LogInfo((object)"Logger Loaded");
maxPlayers = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxPlayers", 8, "The maximum number of players allowed in a lobby.");
Constants.MAX_PLAYERS = maxPlayers.Value;
Host.recordReplay = false;
((BaseUnityPlugin)this).Logger.LogInfo((object)"Disabled replay recording");
harmony = new Harmony("com.MorePlayersTeam.MorePlayers");
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(Main).GetMethod("SteamManagerCreateFriendLobbyPatch", BindingFlags.Static | BindingFlags.NonPublic);
PatchProcessor val = harmony.CreateProcessor((MethodBase)method2);
val.AddTranspiler(method3);
val.Patch();
((BaseUnityPlugin)this).Logger.LogInfo((object)$"More players acquired! Max players: {Constants.MAX_PLAYERS}");
}
private void OnDestroy()
{
harmony.UnpatchSelf();
}
}
[HarmonyPatch(typeof(printText))]
[HarmonyPatch("Awake")]
public static class PatchVersion
{
public static void Prefix()
{
Main.Log.LogInfo((object)("Found version " + Constants.version));
Constants.version += "-More Players Modded";
Main.Log.LogInfo((object)("Patched to version " + Constants.version));
}
}
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)
Main.Log.LogInfo((object)$"MultiInputPacket: {inputPackets.Count} input packets");
foreach (KeyValuePair<int, InputPacket> inputPacket in inputPackets)
{
Main.Log.LogInfo((object)$"Player {inputPacket.Key}:");
Main.Log.LogInfo((object)$"seqNumber: {inputPacket.Value.seqNumber}");
Main.Log.LogInfo((object)$"joystickAngle: {inputPacket.Value.joystickAngle}");
Main.Log.LogInfo((object)$"jump: {inputPacket.Value.jump}");
Main.Log.LogInfo((object)$"ab1: {inputPacket.Value.ab1}");
Main.Log.LogInfo((object)$"ab2: {inputPacket.Value.ab2}");
Main.Log.LogInfo((object)$"ab3: {inputPacket.Value.ab3}");
Main.Log.LogInfo((object)$"start: {inputPacket.Value.start}");
Main.Log.LogInfo((object)$"select: {inputPacket.Value.select}");
Main.Log.LogInfo((object)$"w: {inputPacket.Value.w}");
Main.Log.LogInfo((object)$"a: {inputPacket.Value.a}");
Main.Log.LogInfo((object)$"s: {inputPacket.Value.s}");
Main.Log.LogInfo((object)$"d: {inputPacket.Value.d}");
Main.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)
{
Main.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));
Main.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));
Main.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++];
Main.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));
Main.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++];
Main.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++];
Main.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++];
Main.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++];
Main.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++];
Main.Log.LogInfo((object)$"Decoded p_ability3s[{n}]: {result.p_ability3s[n]} (byte: {num})");
}
return result;
}
public static void EncodeMultiStartRequest(ref byte[] data, MultiStartRequestPacket p)
{
Main.Log.LogInfo((object)$"Encoding MultiStartRequestPacket, size of array: {data.Length}");
int num = 0;
Main.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];
Main.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;
Main.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++)
{
Main.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];
Main.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];
Main.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];
Main.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];
Main.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];
Main.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);
}
}
}
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)
Main.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 = Main.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++)
{
Main.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)];
Main.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()
{
Main.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
Main.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
{
[HarmonyPatch(typeof(SteamManager))]
[HarmonyPatch("KickPlayer")]
private static class SteamManagerPatch_KickPlayer
{
private static void Prefix(ref int connectedPlayerIndex, SteamManager __instance)
{
connectedPlayerIndex = Mathf.Clamp(connectedPlayerIndex, 0, __instance.connectedPlayers.Count - 1);
}
}
private static bool Prefix(SteamManager __instance, Player hostPlayer, NamedSpriteList abilityIcons)
{
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
Main.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)
{
Main.Log.LogInfo((object)i);
return i;
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
Main.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())
{
Main.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)
{
Main.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 = Main.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;
}
}
[HarmonyPatch(typeof(SteamFrame))]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal class SteamFrame_Awake_Patch
{
private static void Prefix(SteamFrame __instance)
{
if (__instance.squares.Count == 4)
{
for (int i = 0; i < 4; i++)
{
SteamFrameButton val = Object.Instantiate<SteamFrameButton>(__instance.squares[i]);
((Component)val).transform.SetParent(((Component)__instance.squares[i]).transform.parent, false);
__instance.squares.Add(val);
}
}
}
}
[HarmonyPatch(typeof(SteamFrame))]
[HarmonyPatch(/*Could not decode attribute arguments.*/)]
internal class SteamFrame_Update_Patch
{
private static void Postfix(SteamFrame __instance)
{
__instance.nrOfSquares = Mathf.Min(__instance.squares.Count, 4);
for (int i = 0; i < __instance.squares.Count; i++)
{
((Component)__instance.squares[i]).gameObject.SetActive(i < __instance.nrOfSquares);
}
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "MorePlayers";
public const string PLUGIN_NAME = "MorePlayers";
public const string PLUGIN_VERSION = "1.0.0";
}
}