Due to update 2.4.3, some mods may no longer function. FixedConfig may be necessary.
Decompiled source of MorePlayers v1.0.0
MorePlayers.dll
Decompiled 2 days agousing System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BoplFixedMath; using HarmonyLib; using Steamworks; using Steamworks.Data; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace MorePlayers; internal static class PerPlayerSounds { private static readonly string[] Prefixes = new string[4] { "slimeJump", "slimeWalk", "slimeLand", "beamCharge" }; public static string Remap(string name) { if (string.IsNullOrEmpty(name) || (name[0] != 's' && name[0] != 'b')) { return name; } for (int i = 0; i < Prefixes.Length; i++) { string text = Prefixes[i]; if (name.Length > text.Length && name.StartsWith(text) && int.TryParse(name.Substring(text.Length), out var result) && ExtraPlayers.IsExtraId(result)) { return text + ((result - 7) % 4 + 1); } } return name; } } [HarmonyPatch(typeof(AudioManager), "Play", new Type[] { typeof(string), typeof(float) })] internal static class PlaySoundPatch { private static void Prefix(ref string name) { name = PerPlayerSounds.Remap(name); } } [HarmonyPatch(typeof(AudioManager), "Play", new Type[] { typeof(string), typeof(float), typeof(float) })] internal static class PlaySoundPitchPatch { private static void Prefix(ref string name) { name = PerPlayerSounds.Remap(name); } } [HarmonyPatch(typeof(AudioManager), "PlayInterruptable")] internal static class PlayInterruptablePatch { private static void Prefix(ref string name) { name = PerPlayerSounds.Remap(name); } } [HarmonyPatch(typeof(AudioManager), "TimesSoundsPlayed")] internal static class TimesSoundsPlayedPatch { private static bool Prefix(InterruptableAudio interruptableAudio, ref int __result) { if (interruptableAudio.index < 0) { __result = 0; return false; } return true; } } [HarmonyPatch(typeof(CharacterSelectHandler), "TryStartGame_inner")] internal static class DebugBots { private static readonly FieldInfo AllReadyField = AccessTools.Field(typeof(CharacterSelectHandler), "allReadyForMoreThanOneFrame"); private static readonly FieldInfo PlayerColorsField = AccessTools.Field(typeof(CharacterSelectHandler), "playerColors"); private static void Prefix(out bool __state) { __state = CharacterSelectHandler.startButtonAvailable && (bool)AllReadyField.GetValue(null); } private static void Postfix(CharacterSelectHandler __instance, bool __state) { if (!__state) { return; } ReplayGuard.SetBigGame(MorePlayersPlugin.DebugBots > 0); if (MorePlayersPlugin.DebugBots <= 0) { return; } Safe.Run("adding debug bots", delegate { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) List<Player> list = PlayerHandler.Get().PlayerList(); if (list.Count != 0) { PlayerColors val = (PlayerColors)PlayerColorsField.GetValue(__instance); Player val2 = list[0]; int val3 = Math.Min(MorePlayersPlugin.DebugBots, MorePlayersPlugin.MaxPlayers - list.Count); val3 = Math.Min(val3, 8); int num = Math.Max(TeamColorExtender.TeamCount(), 4); int i = 0; int j = 0; int num2 = -1; for (int k = 0; k < val3; k++) { if (num2 < 0 || !MorePlayersPlugin.DebugBotsOneTeam) { for (; i < num - 1 && TeamTaken(list, i); i++) { } num2 = i++; } for (; j < val.Length - 1 && ColorTaken(list, val[j].playerMaterial); j++) { } Player val4 = new Player(7 + k, num2); val4.Color = val[j++].playerMaterial; val4.IsLocalPlayer = false; val4.UsesKeyboardAndMouse = false; val4.CanUseAbilities = true; val4.Abilities = new List<GameObject>(val2.Abilities); val4.AbilityIcons = new List<Sprite>(val2.AbilityIcons); list.Add(val4); } MorePlayersPlugin.Log.LogInfo((object)("Added " + val3 + " debug bots to the local game.")); } }); } private static bool TeamTaken(List<Player> list, int team) { for (int i = 0; i < list.Count; i++) { if (list[i].Team == team) { return true; } } return false; } private static bool ColorTaken(List<Player> list, Material material) { for (int i = 0; i < list.Count; i++) { if ((Object)(object)list[i].Color == (Object)(object)material) { return true; } } return false; } } [HarmonyPatch(typeof(CharacterSelectHandler), "LoadPreviousChoices")] internal static class RemoveDebugBots { private static void Prefix() { Safe.Run("removing debug bots", delegate { PlayerHandler.Get().PlayerList().RemoveAll((Player p) => ExtraPlayers.IsExtraId(p.Id)); }); } } internal class ExtraPlayer { public byte Id; public ulong SteamId; public byte Color; public byte Team; public byte Ability1; public byte Ability2; public byte Ability3; } internal static class ExtraPlayers { public const byte FirstId = 7; public const int MaxExtras = 8; public const int PacketSize = 777; private const int HeaderSize = 5; private const int EntrySize = 14; private static readonly byte[] Magic = new byte[4] { 66, 77, 80, 1 }; public static List<ExtraPlayer> Current = new List<ExtraPlayer>(); public static bool IsExtraId(int id) { if (id >= 7) { return id < 15; } return false; } public static ExtraPlayer FindBySteamId(ulong steamId) { for (int i = 0; i < Current.Count; i++) { if (Current[i].SteamId == steamId) { return Current[i]; } } return null; } public static byte[] Encode(List<ExtraPlayer> extras) { byte[] array = new byte[777]; Magic.CopyTo(array, 0); int num = Mathf.Min(extras.Count, 8); array[4] = (byte)num; int num2 = 5; for (int i = 0; i < num; i++) { ExtraPlayer extraPlayer = extras[i]; array[num2++] = extraPlayer.Id; ulong steamId = extraPlayer.SteamId; for (int j = 0; j < 8; j++) { array[num2++] = (byte)(steamId >> 8 * j); } array[num2++] = extraPlayer.Color; array[num2++] = extraPlayer.Team; array[num2++] = extraPlayer.Ability1; array[num2++] = extraPlayer.Ability2; array[num2++] = extraPlayer.Ability3; } return array; } public static bool IsExtrasPacket(byte[] data, int size) { if (size != 777) { return false; } for (int i = 0; i < Magic.Length; i++) { if (data[i] != Magic[i]) { return false; } } return data[4] <= 8; } public static List<ExtraPlayer> Decode(byte[] data) { List<ExtraPlayer> list = new List<ExtraPlayer>(); int num = data[4]; int num2 = 5; for (int i = 0; i < num; i++) { ExtraPlayer extraPlayer = new ExtraPlayer(); extraPlayer.Id = data[num2++]; ulong num3 = 0uL; for (int j = 0; j < 8; j++) { num3 |= (ulong)data[num2++] << 8 * j; } extraPlayer.SteamId = num3; extraPlayer.Color = data[num2++]; extraPlayer.Team = data[num2++]; extraPlayer.Ability1 = data[num2++]; extraPlayer.Ability2 = data[num2++]; extraPlayer.Ability3 = data[num2++]; if (IsExtraId(extraPlayer.Id)) { list.Add(extraPlayer); } } return list; } public static void Broadcast() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) byte[] array = Encode(Current); List<SteamConnection> connectedPlayers = SteamManager.instance.connectedPlayers; for (int i = 0; i < connectedPlayers.Count; i++) { ((Connection)(ref ((ConnectionManager)connectedPlayers[i]).Connection)).SendMessage(array, (SendType)8); } } public static ExtraPlayer FromConnection(byte id, SteamConnection connection) { ExtraPlayer extraPlayer = new ExtraPlayer(); extraPlayer.Id = id; extraPlayer.SteamId = connection.id.Value; extraPlayer.Color = (byte)connection.lobby_color; extraPlayer.Team = connection.lobby_team; extraPlayer.Ability1 = connection.lobby_ability1; extraPlayer.Ability2 = connection.lobby_ability2; extraPlayer.Ability3 = connection.lobby_ability3; return extraPlayer; } public static void ApplyAbilities(Player player, ExtraPlayer extra, int nrOfAbilities) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) NamedSpriteList abilityIcons = SteamManager.instance.abilityIcons; player.Abilities.Clear(); player.AbilityIcons.Clear(); byte[] array = new byte[3] { extra.Ability1, extra.Ability2, extra.Ability3 }; for (int i = 0; i < nrOfAbilities && i < array.Length; i++) { player.Abilities.Add(abilityIcons.sprites[array[i]].associatedGameObject); player.AbilityIcons.Add(abilityIcons.sprites[array[i]].sprite); } } } internal static class ExtraInputs { public static readonly Queue<InputPacket[]> Buffer = new Queue<InputPacket[]>(); private static readonly FieldInfo PreviousQuadField = AccessTools.Field(typeof(Host), "previousInputQuad"); public static void Store(ref InputPacketQuad quad, ref InputPacket[] extras, int playerId, InputPacket input) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_005b: Unknown result type (might be due to invalid IL or missing references) switch (playerId) { case 1: quad.p1 = input; return; case 2: quad.p2 = input; return; case 3: quad.p3 = input; return; case 4: quad.p4 = input; return; } if (ExtraPlayers.IsExtraId(playerId)) { if (extras == null) { extras = (InputPacket[])(object)new InputPacket[8]; } extras[playerId - 7] = input; } } public static void ApplyBeforeTick(Host host) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (Buffer.Count == 0) { return; } InputPacket[] array = Buffer.Dequeue(); List<Player> list = PlayerHandler.Get().PlayerList(); for (int i = 0; i < list.Count; i++) { int id = list[i].Id; if (ExtraPlayers.IsExtraId(id)) { list[i].OverrideInputWithNetworkInput((InputPacket)((array == null) ? default(InputPacket) : array[id - 7])); } } if (array != null) { AddDelayVotes(host, array); } } private static void AddDelayVotes(Host host, InputPacket[] frame) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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) byte b = 0; for (int i = 0; i < frame.Length; i++) { if (frame[i].targetDelayBufferSize > b) { b = frame[i].targetDelayBufferSize; } } InputPacketQuad val = (InputPacketQuad)PreviousQuadField.GetValue(host); if (b > val.p1.targetDelayBufferSize) { val.p1.targetDelayBufferSize = b; PreviousQuadField.SetValue(host, val); } } } [HarmonyPatch(typeof(Host), "Init")] internal static class HostInitPatch { private static void Postfix() { ExtraInputs.Buffer.Clear(); } } [HarmonyPatch(typeof(Host), "ProcessNetworkPackets")] internal static class ProcessNetworkPacketsPatch { private static readonly FieldInfo ClientsField = AccessTools.Field(typeof(Host), "clients"); private static readonly FieldInfo LocalPlayerIdField = AccessTools.Field(typeof(Host), "localPlayerId"); private static readonly FieldInfo InputHistoryField = AccessTools.Field(typeof(Host), "inputHistory"); private static readonly FieldInfo AllClientsSyncedField = AccessTools.Field(typeof(Host), "allClientsSynced"); private static readonly FieldInfo InputBufferField = AccessTools.Field(typeof(Host), "InputBuffer"); private static readonly FieldInfo DelayBufferSizeField = AccessTools.Field(typeof(Host), "delayBufferSize"); private static readonly FieldInfo UpdatesPlacedField = AccessTools.Field(typeof(Host), "UpdatesPlacedInDelayBuffer"); private static readonly FieldInfo SentPacketHistoryField = AccessTools.Field(typeof(Host), "sentPacketHistory"); private static bool Prefix(Host __instance) { //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) List<Client> list = (List<Client>)ClientsField.GetValue(__instance); int num = (int)LocalPlayerIdField.GetValue(__instance); TimedInputPacket[] array = (TimedInputPacket[])InputHistoryField.GetValue(__instance); Queue<InputPacketQuad> queue = (Queue<InputPacketQuad>)InputBufferField.GetValue(__instance); if (list.Count == 0) { MonoBehaviour.print((object)"There are no clients"); } for (int i = 0; i < list.Count; i++) { if (!((ConnectionManager)list[i].steamConnection).Connected && !((ConnectionManager)list[i].steamConnection).Connecting) { MonoBehaviour.print((object)" a client is not connected nor connecting"); } } bool flag = true; for (int j = 0; j < list.Count; j++) { list[j].ProcessNetworkPackets(Time.unscaledTime, array, __instance.AdaptiveInputDelayBuffer, (byte)num); flag &= list[j].HasReceivedSyncAck; flag &= list[j].HasSentSyncAck; } bool flag2 = (bool)AllClientsSyncedField.GetValue(__instance); if (flag && !flag2) { flag2 = true; AllClientsSyncedField.SetValue(__instance, true); int num2 = (int)DelayBufferSizeField.GetValue(null); for (int k = 0; k < num2; k++) { queue.Enqueue(default(InputPacketQuad)); ExtraInputs.Buffer.Enqueue(null); } } if (!flag2) { return false; } uint num3 = uint.MaxValue; for (int l = 0; l < list.Count; l++) { if (list[l].InputPacketsReceived < num3) { num3 = list[l].InputPacketsReceived; } } if (__instance.inputPacketsSent < num3) { num3 = __instance.inputPacketsSent; } int num4 = (int)UpdatesPlacedField.GetValue(__instance); Queue<InputPacket> queue2 = (Queue<InputPacket>)SentPacketHistoryField.GetValue(__instance); int num5 = (int)num3 - num4; for (int m = 0; m < num5; m++) { InputPacketQuad quad = default(InputPacketQuad); InputPacket[] extras = null; for (int n = 0; n < list.Count; n++) { ExtraInputs.Store(ref quad, ref extras, list[n].PlayerId, list[n].inputHistory.Dequeue()); } ExtraInputs.Store(ref quad, ref extras, num, queue2.Dequeue()); queue.Enqueue(quad); ExtraInputs.Buffer.Enqueue(extras); num4++; } UpdatesPlacedField.SetValue(__instance, num4); try { if (num == 1) { for (int num6 = 0; num6 < list.Count; num6++) { list[num6].CheckForDesyncs(); } } } catch (Exception ex) { Debug.LogError((object)("Desync occured, ending game " + ex)); GameSessionHandler.EndGameImmediately(); } return false; } } [HarmonyPatch(typeof(Host), "Update")] internal static class HostUpdatePatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(Updater), "TickSimulation", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(ExtraInputs), "ApplyBeforeTick", (Type[])null, (Type[])null); List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; int index = -1; for (int i = 0; i < list.Count; i++) { if ((list[i].opcode == OpCodes.Call || list[i].opcode == OpCodes.Callvirt) && list[i].operand as MethodInfo == methodInfo) { num++; index = i; } } if (num != 1) { MorePlayersPlugin.Log.LogError((object)("Host.Update looks different than expected (" + num + " ticks found). Players 7+ will not receive input; the game may have updated.")); return list; } CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null); val.labels.AddRange(list[index].labels); list[index].labels.Clear(); list.InsertRange(index, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[2] { val, new CodeInstruction(OpCodes.Call, (object)methodInfo2) }); return list; } } internal static class LobbyMembers { private const string MemberKey = "moreplayers"; private const float GraceSeconds = 10f; public static readonly List<string> Dropped = new List<string>(); public static string Notice; public static float NoticeUntil; private static readonly Dictionary<SteamConnection, float> firstSeen = new Dictionary<SteamConnection, float>(); private static ulong currentLobbyId; private static ulong ownerId; private static float ownerSince; public static void Update() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)SteamManager.instance == (Object)null || !SteamClient.IsValid || string.IsNullOrEmpty(Constants.version)) { return; } Lobby currentLobby = SteamManager.instance.currentLobby; ulong value = ((Lobby)(ref currentLobby)).Id.Value; if (value == 0) { return; } if (value != currentLobbyId) { currentLobbyId = value; firstSeen.Clear(); Dropped.Clear(); ownerId = 0uL; } HashSet<ulong> hashSet = new HashSet<ulong>(); foreach (Friend member in ((Lobby)(ref currentLobby)).Members) { hashSet.Add(member.Id.Value); } if (!hashSet.Contains(SteamClient.SteamId.Value)) { Dropped.Clear(); return; } if (((Lobby)(ref currentLobby)).GetMemberData(new Friend(SteamClient.SteamId), "moreplayers") != Constants.version) { ((Lobby)(ref currentLobby)).SetMemberData("moreplayers", Constants.version); } if (!GameSession.inMenus) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (LeaveIfOwnerIncompatible(currentLobby, realtimeSinceStartup)) { return; } List<SteamConnection> connectedPlayers = SteamManager.instance.connectedPlayers; for (int num = connectedPlayers.Count - 1; num >= 0; num--) { SteamConnection val = connectedPlayers[num]; if (hashSet.Contains(val.id.Value)) { if (!firstSeen.TryGetValue(val, out var value2)) { firstSeen[val] = realtimeSinceStartup; } else if (!(realtimeSinceStartup - value2 < 10f) && !IsCompatible(currentLobby, val.id)) { MorePlayersPlugin.Log.LogWarning((object)(val.steamName + " is in the lobby without this build of More Players; ignoring them.")); Dropped.Add(val.steamName); firstSeen.Remove(val); ((ConnectionManager)val).Close(); connectedPlayers.RemoveAt(num); } } } List<SteamConnection> list = new List<SteamConnection>(); foreach (SteamConnection key in firstSeen.Keys) { if (!connectedPlayers.Contains(key)) { list.Add(key); } } for (int i = 0; i < list.Count; i++) { firstSeen.Remove(list[i]); } } private static bool LeaveIfOwnerIncompatible(Lobby lobby, float now) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (SteamManager.LocalPlayerIsLobbyOwner) { return false; } ulong value = ((Lobby)(ref lobby)).Owner.Id.Value; if (value != ownerId) { ownerId = value; ownerSince = now; return false; } if (now - ownerSince < 10f || IsCompatible(lobby, ((Lobby)(ref lobby)).Owner.Id)) { return false; } MorePlayersPlugin.Log.LogWarning((object)"The lobby owner doesn't have this build of More Players; moving to a new lobby."); ShowNotice("The lobby owner doesn't have More Players 1.0.0.\nYou've been moved to a new lobby - invite your friends again."); SteamManager.instance.LeaveLobby(); return true; } private static bool IsCompatible(Lobby lobby, SteamId id) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) return ((Lobby)(ref lobby)).GetMemberData(new Friend(id), "moreplayers") == Constants.version; } public static void ShowNotice(string text) { Notice = text; NoticeUntil = Time.realtimeSinceStartup + 20f; } public static void LeaveIfIncompatible(Lobby lobby) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) Safe.Run("checking a joined lobby", delegate { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (SteamClient.IsValid && !string.IsNullOrEmpty(Constants.version) && !((Lobby)(ref lobby)).IsOwnedBy(SteamClient.SteamId)) { string data = ((Lobby)(ref lobby)).GetData("version"); if (!string.IsNullOrEmpty(data) && !(data == Constants.version)) { MorePlayersPlugin.Log.LogWarning((object)("Left a lobby running a different version (" + data + ").")); ((Lobby)(ref lobby)).Leave(); } } }); } } [HarmonyPatch(typeof(SteamManager), "HostGame")] internal static class HostGamePatch { private static void Prefix() { Safe.Run("sending extra players at game start", delegate { List<SteamConnection> connectedPlayers = SteamManager.instance.connectedPlayers; List<ExtraPlayer> list = new List<ExtraPlayer>(); for (int i = 3; i < connectedPlayers.Count; i++) { if (list.Count >= 8) { break; } list.Add(ExtraPlayers.FromConnection((byte)(7 + list.Count), connectedPlayers[i])); } ExtraPlayers.Current = list; ReplayGuard.SetBigGame(list.Count > 0); ExtraPlayers.Broadcast(); }); } } [HarmonyPatch(typeof(SteamManager), "HostNextLevel")] internal static class HostNextLevelPatch { private static void Prefix() { Safe.Run("sending extra players for the next level", delegate { List<SteamConnection> connectedPlayers = SteamManager.instance.connectedPlayers; for (int i = 0; i < ExtraPlayers.Current.Count; i++) { ExtraPlayer extraPlayer = ExtraPlayers.Current[i]; for (int j = 0; j < connectedPlayers.Count; j++) { if (connectedPlayers[j].id.Value == extraPlayer.SteamId) { extraPlayer.Ability1 = connectedPlayers[j].lobby_ability1; extraPlayer.Ability2 = connectedPlayers[j].lobby_ability2; extraPlayer.Ability3 = connectedPlayers[j].lobby_ability3; break; } } } ExtraPlayers.Broadcast(); List<Player> list = PlayerHandler.Get().PlayerList(); for (int k = 0; k < list.Count; k++) { for (int l = 0; l < ExtraPlayers.Current.Count; l++) { if (ExtraPlayers.Current[l].Id == list[k].Id) { ExtraPlayers.ApplyAbilities(list[k], ExtraPlayers.Current[l], SteamManager.startParameters.nrOfAbilites); } } } }); } } [HarmonyPatch(typeof(SteamSocket), "OnMessage")] internal static class ReceiveExtraPlayersPatch { private static bool Prefix(NetIdentity identity, IntPtr data, int size) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (size != 777) { return true; } byte[] buffer = new byte[size]; Marshal.Copy(data, buffer, 0, size); if (!ExtraPlayers.IsExtrasPacket(buffer, size)) { return true; } Safe.Run("reading extra players", delegate { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) SteamId steamId = ((NetIdentity)(ref identity)).SteamId; if (((SteamId)(ref steamId)).IsValid && ((Lobby)(ref SteamManager.instance.currentLobby)).IsOwnedBy(((NetIdentity)(ref identity)).SteamId)) { ExtraPlayers.Current = ExtraPlayers.Decode(buffer); ReplayGuard.SetBigGame(ExtraPlayers.Current.Count > 0); } }); return false; } } [HarmonyPatch(typeof(SteamManager), "InitNetworkClient")] internal static class InitNetworkClientPatch { private static bool Prefix(SteamManager __instance) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Expected O, but got Unknown StartRequestPacket startParameters = SteamManager.startParameters; ulong value = SteamClient.SteamId.Value; int num = 0; if (startParameters.p1_id == value) { num = 1; } else if (startParameters.p2_id == value) { num = 2; } else if (startParameters.p3_id == value) { num = 3; } else if (startParameters.p4_id == value) { num = 4; } else { ExtraPlayer extraPlayer = ExtraPlayers.FindBySteamId(value); if (extraPlayer != null) { num = extraPlayer.Id; } } List<Client> list = new List<Client>(); List<SteamConnection> connectedPlayers = __instance.connectedPlayers; for (int i = 0; i < connectedPlayers.Count; i++) { ulong value2 = connectedPlayers[i].id.Value; if (value2 == startParameters.p1_id && startParameters.nrOfPlayers >= 1) { list.Add(new Client(1, connectedPlayers[i])); continue; } if (value2 == startParameters.p2_id && startParameters.nrOfPlayers >= 2) { list.Add(new Client(2, connectedPlayers[i])); continue; } if (value2 == startParameters.p3_id && startParameters.nrOfPlayers >= 3) { list.Add(new Client(3, connectedPlayers[i])); continue; } if (value2 == startParameters.p4_id && startParameters.nrOfPlayers >= 4) { list.Add(new Client(4, connectedPlayers[i])); continue; } ExtraPlayer extraPlayer2 = ExtraPlayers.FindBySteamId(value2); if (extraPlayer2 != null) { list.Add(new Client((int)extraPlayer2.Id, connectedPlayers[i])); } } __instance.networkClient.Init(list, num, startParameters.currentLevel, __instance.startFrameBuffer, __instance.checkForDesyncs); SteamManager.networkClientHandle = __instance.networkClient; return false; } } [HarmonyPatch(typeof(CharacterSelectHandler_online), "ForceStartGame")] internal static class ForceStartGamePatch { private static readonly FieldInfo SelfRef = AccessTools.Field(typeof(CharacterSelectHandler_online), "selfRef"); private static bool Prefix(PlayerColors pcs) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)pcs == (Object)null) { pcs = ((CharacterSelectHandler_online)SelfRef.GetValue(null)).playerColors; } if (GameLobby.isPlayingAReplay) { ExtraPlayers.Current = new List<ExtraPlayer>(); } ReplayGuard.SetBigGame(ExtraPlayers.Current.Count > 0); StartRequestPacket startParameters = SteamManager.startParameters; Updater.ReInit(); List<Player> list = new List<Player>(); Updater.InitSeed(startParameters.seed); int num = 0; if (startParameters.p1_ability1 != 0 && startParameters.nrOfPlayers > num) { list.Add(InitPlayer(1, startParameters.p1_color, startParameters.p1_team, startParameters.p1_ability1, startParameters.p1_ability2, startParameters.p1_ability3, startParameters.nrOfAbilites, pcs)); num++; } if (startParameters.p2_ability1 != 0 && startParameters.nrOfPlayers > num) { list.Add(InitPlayer(2, startParameters.p2_color, startParameters.p2_team, startParameters.p2_ability1, startParameters.p2_ability2, startParameters.p2_ability3, startParameters.nrOfAbilites, pcs)); num++; } if (startParameters.p3_ability1 != 0 && startParameters.nrOfPlayers > num) { list.Add(InitPlayer(3, startParameters.p3_color, startParameters.p3_team, startParameters.p3_ability1, startParameters.p3_ability2, startParameters.p3_ability3, startParameters.nrOfAbilites, pcs)); num++; } if (startParameters.p4_ability1 != 0 && startParameters.nrOfPlayers > num) { list.Add(InitPlayer(4, startParameters.p4_color, startParameters.p4_team, startParameters.p4_ability1, startParameters.p4_ability2, startParameters.p4_ability3, startParameters.nrOfAbilites, pcs)); num++; } for (int i = 0; i < ExtraPlayers.Current.Count; i++) { ExtraPlayer extraPlayer = ExtraPlayers.Current[i]; Player val = InitPlayer(extraPlayer.Id, extraPlayer.Color, extraPlayer.Team, extraPlayer.Ability1, extraPlayer.Ability2, extraPlayer.Ability3, startParameters.nrOfAbilites, pcs); val.steamId = SteamId.op_Implicit(extraPlayer.SteamId); list.Add(val); } for (int j = 0; j < list.Count; j++) { switch (list[j].Id) { case 1: list[j].steamId = SteamId.op_Implicit(startParameters.p1_id); break; case 2: list[j].steamId = SteamId.op_Implicit(startParameters.p2_id); break; case 3: list[j].steamId = SteamId.op_Implicit(startParameters.p3_id); break; case 4: list[j].steamId = SteamId.op_Implicit(startParameters.p4_id); break; } } Player val2 = null; if (GameLobby.isPlayingAReplay) { val2 = list[0]; } else { ulong value = SteamClient.SteamId.Value; for (int k = 0; k < list.Count; k++) { if (list[k].steamId.Value == value) { val2 = list[k]; break; } } } if (val2 == null) { MorePlayersPlugin.Log.LogError((object)"Could not find the local player in the start request, leaving the game."); GameSessionHandler.LeaveGame(true, false); return false; } 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 val3 = AudioManager.Get(); if ((Object)(object)val3 != (Object)null) { val3.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; } private static Player InitPlayer(int id, byte color, byte team, byte ability1, byte ability2, byte ability3, int nrOfAbilities, PlayerColors playerColors) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown Player val = new Player(); val.Id = id; val.Color = playerColors.playerColors[color].playerMaterial; val.Team = team; ExtraPlayer extraPlayer = new ExtraPlayer(); extraPlayer.Ability1 = ability1; extraPlayer.Ability2 = ability2; extraPlayer.Ability3 = ability3; ExtraPlayers.ApplyAbilities(val, extraPlayer, nrOfAbilities); val.IsLocalPlayer = false; return val; } } [HarmonyPatch(typeof(SteamManager), "ForceLoadNextLevel")] internal static class ForceLoadNextLevelPatch { private static void Prefix() { Safe.Run("updating extra players' abilities", delegate { List<Player> list = PlayerHandler.Get().PlayerList(); for (int i = 0; i < list.Count; i++) { if (ExtraPlayers.IsExtraId(list[i].Id)) { for (int j = 0; j < ExtraPlayers.Current.Count; j++) { if (ExtraPlayers.Current[j].Id == list[i].Id) { ExtraPlayers.ApplyAbilities(list[i], ExtraPlayers.Current[j], SteamManager.startParameters.nrOfAbilites); } } } } }); } } [HarmonyPatch(typeof(CharacterSelectHandler_online), "SetTeamColor")] internal static class SetTeamColorPatch { private static void Prefix(ref int colorId) { int num = TeamColorExtender.TeamCount(); if (num > 0 && colorId >= num) { colorId %= num; } } } [HarmonyPatch(typeof(SteamManager), "ForceBacktoAbilitySelect")] internal static class ClearClientsAfterMatchPatch { private static void Postfix() { Safe.Run("clearing last match's players", delegate { Host networkClientHandle = SteamManager.networkClientHandle; if ((Object)(object)networkClientHandle != (Object)null && !networkClientHandle.hasBeenInitialized) { networkClientHandle.ClearClients(); } }); } } internal static class ReplayGuard { private static bool paused; private static bool savedValue; public static void SetBigGame(bool big) { if (big && !paused) { savedValue = Host.recordReplay; Host.recordReplay = false; paused = true; } else if (!big && paused) { Host.recordReplay = savedValue; paused = false; } } } [BepInPlugin("com.boplmods.moreplayers", "More Players", "1.0.0")] public class MorePlayersPlugin : BaseUnityPlugin { public const string Guid = "com.boplmods.moreplayers"; public const string Version = "1.0.0"; public const int HardMaxPlayers = 12; public const string VersionTag = " + More Players 1.0.0"; internal static ManualLogSource Log; internal static int MaxPlayers = 12; internal static int DebugBots; internal static bool DebugBotsOneTeam; private static MorePlayersRunner runner; private void Awake() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; ConfigEntry<int> val = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxPlayers", 12, new ConfigDescription("Most players allowed in an online lobby. The game has 12 slime colours, so 12 is the limit.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 12), new object[0])); ConfigEntry<int> val2 = ((BaseUnityPlugin)this).Config.Bind<int>("Testing", "DebugBots", 0, new ConfigDescription("Adds this many standing-still dummy slimes to LOCAL games so you can preview big matches alone. Leave at 0 for normal play.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 11), new object[0])); ConfigEntry<bool> val3 = ((BaseUnityPlugin)this).Config.Bind<bool>("Testing", "DebugBotsOneTeam", true, "Put all dummy slimes on one team, so a round ends as soon as you lose or beat them."); MaxPlayers = Mathf.Clamp(val.Value, 2, 12); DebugBots = val2.Value; DebugBotsOneTeam = val3.Value; if (Constants.MAX_PLAYERS < MaxPlayers) { Constants.MAX_PLAYERS = MaxPlayers; } new Harmony("com.boplmods.moreplayers").PatchAll(typeof(MorePlayersPlugin).Assembly); SceneManager.sceneLoaded += OnSceneLoaded; SteamMatchmaking.OnLobbyEntered += LobbyMembers.LeaveIfIncompatible; Log.LogInfo((object)("More Players 1.0.0 loaded: up to " + MaxPlayers + " players per online lobby.")); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown Safe.Run("extending team colours", TeamColorExtender.ExtendAll); Spawns.OnSceneLoaded(); if ((Object)(object)runner == (Object)null) { GameObject val = new GameObject("MorePlayersRunner"); ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val); runner = val.AddComponent<MorePlayersRunner>(); } } } internal class MorePlayersRunner : MonoBehaviour { private float lobbyCheckTimer; private static ulong loggedLobby; private static MorePlayersRunner instance; private static readonly string ScreenshotFlag = Path.Combine(Paths.BepInExRootPath, "moreplayers-screenshot.flag"); private void Awake() { instance = this; } public static void CaptureMainMenuIfRequested() { if ((Object)(object)instance != (Object)null && File.Exists(ScreenshotFlag)) { File.Delete(ScreenshotFlag); ((MonoBehaviour)instance).StartCoroutine(CaptureSoon()); } } private static IEnumerator CaptureSoon() { yield return (object)new WaitForSecondsRealtime(4f); ScreenCapture.CaptureScreenshot(Path.Combine(Paths.BepInExRootPath, "moreplayers-mainmenu.png")); } private void Update() { lobbyCheckTimer -= Time.unscaledDeltaTime; if (!(lobbyCheckTimer > 0f)) { lobbyCheckTimer = 2f; Safe.Run("updating lobby size", KeepLobbyBigEnough); Safe.Run("checking lobby members", LobbyMembers.Update); } } private void OnGUI() { Safe.Run("drawing the lobby list", LobbyOverlay.Draw); } private static void KeepLobbyBigEnough() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)SteamManager.instance == (Object)null) && SteamClient.IsValid && ((Lobby)(ref SteamManager.instance.currentLobby)).Id.Value != 0 && SteamManager.LocalPlayerIsLobbyOwner) { int maxPlayers = MorePlayersPlugin.MaxPlayers; if (((Lobby)(ref SteamManager.instance.currentLobby)).MaxMembers < maxPlayers) { ((Lobby)(ref SteamManager.instance.currentLobby)).MaxMembers = maxPlayers; } ulong value = ((Lobby)(ref SteamManager.instance.currentLobby)).Id.Value; if (value != loggedLobby) { loggedLobby = value; MorePlayersPlugin.Log.LogInfo((object)("Your lobby allows " + ((Lobby)(ref SteamManager.instance.currentLobby)).MaxMembers + " players (version tag: " + Constants.version + ")")); } if (!string.IsNullOrEmpty(Constants.version) && ((Lobby)(ref SteamManager.instance.currentLobby)).GetData("version") != Constants.version) { ((Lobby)(ref SteamManager.instance.currentLobby)).SetData("version", Constants.version); } } } } internal static class Safe { public static void Run(string what, Action action) { try { action(); } catch (Exception ex) { MorePlayersPlugin.Log.LogError((object)("Error while " + what + ": " + ex)); } } } [HarmonyPatch(typeof(printText), "Awake")] internal static class TagGameVersion { private static void Postfix(printText __instance) { Safe.Run("tagging the game version", delegate { if (Constants.version != null && !Constants.version.EndsWith(" + More Players 1.0.0")) { Constants.version += " + More Players 1.0.0"; } }); } } [HarmonyPatch(typeof(printText), "Start")] internal static class ShowModVersion { private static void Postfix(printText __instance) { Safe.Run("showing the mod version", delegate { VersionLabel.Add(__instance); MorePlayersRunner.CaptureMainMenuIfRequested(); }); } } internal static class VersionLabel { private const string ObjectName = "MorePlayersVersion"; public static void Add(printText owner) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI component = ((Component)owner).GetComponent<TextMeshProUGUI>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)((Component)owner).transform.Find("MorePlayersVersion") != (Object)null)) { ((TMP_Text)component).ForceMeshUpdate(false, false); Bounds textBounds = ((TMP_Text)component).textBounds; GameObject val = new GameObject("MorePlayersVersion", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(((TMP_Text)component).transform, false); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)val2).font = ((TMP_Text)component).font; ((TMP_Text)val2).fontSharedMaterial = ((TMP_Text)component).fontSharedMaterial; ((Graphic)val2).color = ((Graphic)component).color; ((TMP_Text)val2).fontSize = ((TMP_Text)component).fontSize * 0.4f; ((TMP_Text)val2).alignment = (TextAlignmentOptions)1028; ((TMP_Text)val2).enableWordWrapping = false; ((TMP_Text)val2).overflowMode = (TextOverflowModes)0; ((Graphic)val2).raycastTarget = false; ((TMP_Text)val2).text = "More Players"; RectTransform rectTransform = ((TMP_Text)val2).rectTransform; rectTransform.anchorMin = ((TMP_Text)component).rectTransform.pivot; rectTransform.anchorMax = ((TMP_Text)component).rectTransform.pivot; rectTransform.pivot = new Vector2(1f, 0f); rectTransform.sizeDelta = new Vector2(((TMP_Text)val2).preferredWidth + 10f, ((TMP_Text)val2).preferredHeight); rectTransform.anchoredPosition = new Vector2(((Bounds)(ref textBounds)).max.x, ((Bounds)(ref textBounds)).max.y + ((TMP_Text)component).fontSize * 0.1f); } } } [HarmonyPatch(typeof(CharacterSelectHandler_online), "CheckForMods")] internal static class ReportModded { private static void Postfix() { CharacterSelectHandler_online.hasMods = true; } } [HarmonyPatch(typeof(SteamMatchmaking), "CreateLobbyAsync")] internal static class BiggerLobbies { private static void Prefix(ref int maxMembers) { if (maxMembers < MorePlayersPlugin.MaxPlayers) { maxMembers = MorePlayersPlugin.MaxPlayers; } } } internal static class TeamColorExtender { private static readonly string[][] ExtraTeams = new string[8][] { new string[3] { "#D9BE29", "#6B5A0D", "#FFE600" }, new string[3] { "#2BB8C4", "#0F5B61", "#19EEFF" }, new string[3] { "#E8891C", "#7A4108", "#FF9F00" }, new string[3] { "#E57A9A", "#7D2B45", "#FF8FB4" }, new string[3] { "#8065D6", "#372874", "#9375FF" }, new string[3] { "#E3E3E3", "#7D7D7D", "#FFFFFF" }, new string[3] { "#9E9E9E", "#474747", "#C9C9C9" }, new string[3] { "#4D4D4D", "#1A1A1A", "#787878" } }; private static TeamColors known; public static int TeamCount() { if (!((Object)(object)known != (Object)null)) { return 0; } return known.Length; } public static void ExtendAll() { TeamColors[] array = Resources.FindObjectsOfTypeAll<TeamColors>(); for (int i = 0; i < array.Length; i++) { Extend(array[i]); known = array[i]; } } private static void Extend(TeamColors colors) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) int num = colors.teamColors.Length; int num2 = 12; if (num != 0 && num < num2) { TeamColor[] array = (TeamColor[])(object)new TeamColor[num2]; Array.Copy(colors.teamColors, array, num); for (int i = num; i < num2; i++) { string[] array2 = ExtraTeams[(i - num) % ExtraTeams.Length]; TeamColor val = new TeamColor { team = i, fill = Parse(array2[0]), border = Parse(array2[1]), saturated = Parse(array2[2]) }; array[i] = val; } colors.teamColors = array; MorePlayersPlugin.Log.LogInfo((object)("Added " + (num2 - num) + " team colours to " + ((Object)colors).name)); } } private static Color Parse(string hex) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) Color result = default(Color); ColorUtility.TryParseHtmlString(hex, ref result); return result; } } [HarmonyPatch(typeof(GameSessionHandler), "SpawnPlayers")] internal static class Spawns { private static readonly Dictionary<int, Vec2[]> originalSpawns = new Dictionary<int, Vec2[]>(); private static Vec2[] plan; private static int nextPlayer; public static void OnSceneLoaded() { originalSpawns.Clear(); } private static void Prefix(GameSessionHandler __instance) { plan = null; nextPlayer = 0; Safe.Run("planning spawn positions", delegate { //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: 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_01c6: Unknown result type (might be due to invalid IL or missing references) List<Player> list = PlayerHandler.Get().PlayerList(); if (list.Count > 4) { int instanceID = ((Object)__instance).GetInstanceID(); if (!originalSpawns.TryGetValue(instanceID, out var value)) { value = (Vec2[])__instance.teamSpawns.Clone(); originalSpawns[instanceID] = value; } if (value.Length != 0) { List<int> list2 = new List<int>(); for (int i = 0; i < list.Count; i++) { if (!list2.Contains(list[i].Team)) { list2.Add(list[i].Team); } } list2.Sort(); if (__instance.teamSpawns.Length < list2.Count) { Vec2[] array = (Vec2[])(object)new Vec2[list2.Count]; for (int j = 0; j < array.Length; j++) { ref Vec2 reference = ref array[j]; reference = value[j % value.Length]; } __instance.teamSpawns = array; } Fix teammateSpawnSpacing = __instance.teammateSpawnSpacing; Fix val = (Fix)0.5; int[] array2 = new int[value.Length]; plan = (Vec2[])(object)new Vec2[list.Count]; Vec2 val4 = default(Vec2); for (int k = 0; k < list.Count; k++) { int num = list2.IndexOf(list[k].Team) % value.Length; int num2 = array2[num]++; switch (num2) { case 0: ((Vec2)(ref val4))..ctor(Fix.Zero, Fix.Zero); break; case 1: ((Vec2)(ref val4))..ctor(-teammateSpawnSpacing, -teammateSpawnSpacing * val); break; case 2: ((Vec2)(ref val4))..ctor(teammateSpawnSpacing, -teammateSpawnSpacing * val); break; default: { int num3 = num2 - 3; Fix val2 = (Fix)(long)(num3 % 3 - 1); Fix val3 = (Fix)(long)(num3 / 3 + 1); ((Vec2)(ref val4))..ctor(val2 * teammateSpawnSpacing, val3 * teammateSpawnSpacing * (Fix)1.5); break; } } ref Vec2 reference2 = ref plan[k]; reference2 = value[num] + val4; } } } }); } public static Vec2 Adjust(Vec2 original) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) int num = nextPlayer++; if (plan == null || num >= plan.Length) { return original; } return plan[num]; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo methodInfo = AccessTools.Method(typeof(Spawns), "Adjust", (Type[])null, (Type[])null); bool flag = false; bool flag2 = false; for (int i = 0; i < list.Count; i++) { if (!flag && list[i].opcode == OpCodes.Ldc_I4_4 && i + 1 < list.Count && list[i + 1].opcode == OpCodes.Newarr && list[i + 1].operand as Type == typeof(int)) { list[i].opcode = OpCodes.Ldc_I4; list[i].operand = 64; flag = true; } MethodInfo methodInfo2 = list[i].operand as MethodInfo; if (!flag2 && list[i].opcode == OpCodes.Call && methodInfo2 != null && methodInfo2.Name == "InstantiateFixed" && methodInfo2.DeclaringType == typeof(FixTransform)) { list.Insert(i, new CodeInstruction(OpCodes.Call, (object)methodInfo)); i++; flag2 = true; } } if (!flag || !flag2) { MorePlayersPlugin.Log.LogError((object)"GameSessionHandler.SpawnPlayers looks different than expected; spawn spreading may not work. The game may have updated."); } return list; } } [HarmonyPatch(typeof(CharacterStatsList), "OnEnable")] internal static class WinnerScreenPatch { private const int TeamPictures = 3; private static void Prefix(CharacterStatsList __instance) { Safe.Run("growing the winner screens", delegate { int wanted = CountWinners(); __instance.winnersOfDraw = Grow(__instance.winnersOfDraw, wanted); __instance.teams3v1WinnersRef = Grow(__instance.teams3v1WinnersRef, wanted); }); } private static void Postfix(CharacterStatsList __instance) { Safe.Run("filling the team winner screen", delegate { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown Image[] teams3v1WinnersRef = __instance.teams3v1WinnersRef; if (teams3v1WinnersRef != null && teams3v1WinnersRef.Length > 3) { List<Player> list = new List<Player>(PlayerHandler.Get().PlayerList()); list.Sort((IComparer<Player>?)new PlayerSorter()); int num = CountWinners(); bool flag = num > 3 && !WinnersOnDifferentTeams(); for (int i = 3; i < teams3v1WinnersRef.Length; i++) { bool flag2 = flag && i < num && i < list.Count; ((Component)teams3v1WinnersRef[i]).gameObject.SetActive(flag2); if (flag2) { ((Graphic)teams3v1WinnersRef[i]).material = list[i].Color; } } } }); } private static int CountWinners() { int num = 0; List<Player> list = PlayerHandler.Get().PlayerList(); for (int i = 0; i < list.Count; i++) { if (list[i].IsMostRecentWinner) { num++; } } return num; } private static bool WinnersOnDifferentTeams() { List<Player> list = PlayerHandler.Get().PlayerList(); for (int i = 0; i < list.Count; i++) { for (int j = i + 1; j < list.Count; j++) { if (list[i].IsMostRecentWinner && list[j].IsMostRecentWinner && list[i].Team != list[j].Team) { return true; } } } return false; } private static Image[] Grow(Image[] images, int wanted) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) if (images == null || images.Length == 0 || wanted <= images.Length) { return images; } Image[] array = (Image[])(object)new Image[wanted]; images.CopyTo(array, 0); Image val = images[^1]; ? val2; if (images.Length <= 1) { Rect rect = ((Graphic)val).rectTransform.rect; val2 = new Vector2(((Rect)(ref rect)).width, 0f); } else { val2 = ((Graphic)val).rectTransform.anchoredPosition - ((Graphic)images[^2]).rectTransform.anchoredPosition; } Vector2 val3 = (Vector2)val2; for (int i = images.Length; i < wanted; i++) { Image val4 = Object.Instantiate<Image>(val, ((Component)val).transform.parent); ((Graphic)val4).rectTransform.anchoredPosition = ((Graphic)val).rectTransform.anchoredPosition + val3 * (float)(i - images.Length + 1); array[i] = val4; } return array; } } [HarmonyPatch(typeof(HandleAbilitySelectUI), "Init")] internal static class AbilitySelectLayoutPatch { private static readonly FieldInfo SelectorsField = AccessTools.Field(typeof(HandleAbilitySelectUI), "Selectors"); private static readonly FieldInfo SeparationField = AccessTools.Field(typeof(HandleAbilitySelectUI), "Separation"); private static readonly FieldInfo OriginalPositionField = AccessTools.Field(typeof(AbilitySelectCircle), "originalPosition"); private static readonly FieldInfo TargetPositionField = AccessTools.Field(typeof(AbilitySelectCircle), "targetPosition"); private static void Postfix(HandleAbilitySelectUI __instance) { Safe.Run("laying out the ability select screen", delegate { //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) AbilitySelectCircle[] array = (AbilitySelectCircle[])SelectorsField.GetValue(__instance); if (array != null && array.Length > 4) { float num = (float)SeparationField.GetValue(__instance); int num2 = array.Length; int num3 = ((num2 <= 6) ? num2 : ((num2 + 1) / 2)); int num4 = (num2 + num3 - 1) / num3; float num5 = Mathf.Min(1f, 3f / (float)(num3 - 1)); if (num4 > 1) { num5 *= 0.8f; } float num6 = -1.5f * num; for (int i = 0; i < num2; i++) { AbilitySelectCircle val = array[i]; int num7 = i / num3; int num8 = i % num3; int num9 = Mathf.Min(num3, num2 - num7 * num3); float num10 = num * num5 * (float)(num9 - 1); float num11 = num6 - num10 / 2f + (float)num8 * num * num5; Rect rect = val.trans.rect; float num12 = Mathf.Clamp(((Rect)(ref rect)).height * num5 * 1.05f, num * num5 * 0.8f, num * num5 * 1.6f); float num13 = ((num4 > 1) ? ((num7 == 0) ? (num12 / 2f) : ((0f - num12) / 2f)) : 0f); val.trans.anchoredPosition = new Vector2(num11, val.trans.anchoredPosition.y); ((Transform)val.trans).localScale = new Vector3(num5, num5, 1f); Vector2 val2 = (Vector2)OriginalPositionField.GetValue(val); OriginalPositionField.SetValue(val, (object)new Vector2(num11, val2.y)); Vector2 val3 = (Vector2)TargetPositionField.GetValue(val); TargetPositionField.SetValue(val, (object)new Vector2(val3.x, val3.y + num13)); } } }); } } [HarmonyPatch(typeof(SteamFrame), "Awake")] internal static class SteamFramePatch { private static readonly FieldInfo SelfRefField = AccessTools.Field(typeof(SteamFrame), "selfRef"); private static readonly FieldInfo SquareColorsField = AccessTools.Field(typeof(SteamFrame), "currentSquareColors"); private static void Postfix(SteamFrame __instance) { Safe.Run("adding avatar slots", delegate { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(SteamFrame)SelfRefField.GetValue(null) != (Object)(object)__instance)) { int num = 11; List<SteamFrameButton> squares = __instance.squares; int count = squares.Count; Image[] lookingForPlayersCircles = __instance.lookingForPlayersCircles; if (count >= 2 && count < num && lookingForPlayersCircles != null && lookingForPlayersCircles.Length == count) { RectTransform component = ((Component)squares[count - 1]).GetComponent<RectTransform>(); Vector2 val = component.anchoredPosition - ((Component)squares[count - 2]).GetComponent<RectTransform>().anchoredPosition; for (int i = count; i < num; i++) { SteamFrameButton val2 = Object.Instantiate<SteamFrameButton>(squares[count - 1], ((Component)squares[count - 1]).transform.parent); ((Component)val2).GetComponent<RectTransform>().anchoredPosition = component.anchoredPosition + val * (float)(i - count + 1); ((Graphic)val2.image).material = new Material(((Graphic)squares[count - 1].image).material); ((Graphic)val2.image).materialForRendering.SetColor("_Blue", Color.white); UnityEvent onClick = (UnityEvent)(object)val2.button.onClick; for (int j = 0; j < ((UnityEventBase)onClick).GetPersistentEventCount(); j++) { ((UnityEventBase)onClick).SetPersistentListenerState(j, (UnityEventCallState)0); } int slot = i; SteamFrame frame = __instance; onClick.AddListener((UnityAction)delegate { frame.ClickKickPlayer(slot); }); ((Component)val2).gameObject.SetActive(false); squares.Add(val2); } Image[] array = (Image[])(object)new Image[num]; lookingForPlayersCircles.CopyTo(array, 0); Image val3 = lookingForPlayersCircles[count - 1]; Vector2 val4 = ((Graphic)val3).rectTransform.anchoredPosition - ((Graphic)lookingForPlayersCircles[count - 2]).rectTransform.anchoredPosition; for (int num2 = count; num2 < num; num2++) { Image val5 = Object.Instantiate<Image>(val3, ((Component)val3).transform.parent); ((Graphic)val5).rectTransform.anchoredPosition = ((Graphic)val3).rectTransform.anchoredPosition + val4 * (float)(num2 - count + 1); ((Behaviour)val5).enabled = false; array[num2] = val5; } __instance.lookingForPlayersCircles = array; int[] array2 = new int[num]; for (int num3 = 0; num3 < array2.Length; num3++) { array2[num3] = -1; } SquareColorsField.SetValue(__instance, array2); } } }); } } [HarmonyPatch(typeof(SteamFrame), "HideAllAvatars")] internal static class HideAvatarsPatch { private static Exception Finalizer(Exception __exception) { if (__exception != null) { MorePlayersPlugin.Log.LogWarning((object)("HideAllAvatars: " + __exception.Message)); } return null; } } [HarmonyPatch(typeof(SteamFrame), "ShowAllAvatars")] internal static class ShowAvatarsPatch { private static Exception Finalizer(Exception __exception) { if (__exception != null) { MorePlayersPlugin.Log.LogWarning((object)("ShowAllAvatars: " + __exception.Message)); } return null; } } internal static class LobbyOverlay { private static readonly FieldInfo SelfRefField = AccessTools.Field(typeof(CharacterSelectHandler_online), "selfRef"); private static GUIStyle style; public static void Draw() { float num = 10f; if (LobbyMembers.Notice != null && Time.realtimeSinceStartup < LobbyMembers.NoticeUntil) { num += DrawBox(LobbyMembers.Notice, num) + 6f; } object? value = SelfRefField.GetValue(null); CharacterSelectHandler_online val = (CharacterSelectHandler_online)((value is CharacterSelectHandler_online) ? value : null); if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled || (Object)(object)SteamManager.instance == (Object)null) { return; } List<SteamConnection> connectedPlayers = SteamManager.instance.connectedPlayers; List<SteamConnection> list = new List<SteamConnection>(); for (int i = 0; i < connectedPlayers.Count; i++) { bool flag = false; for (int j = 0; j < val.networkPlayerBoxes.Length; j++) { if (val.networkPlayerBoxes[j].isVisible && val.networkPlayerBoxes[j].connectedPlayer == connectedPlayers[i]) { flag = true; } } if (!flag && ((ConnectionManager)connectedPlayers[i]).Connected) { list.Add(connectedPlayers[i]); } } if (list.Count == 0 && LobbyMembers.Dropped.Count == 0) { return; } string text = "Lobby: " + (connectedPlayers.Count + 1) + " / " + MorePlayersPlugin.MaxPlayers + " players"; if (list.Count > 0) { text += "\nAlso here:"; } for (int k = 0; k < list.Count; k++) { text = text + "\n " + list[k].steamName + (list[k].lobby_isReady ? " - READY" : " - choosing"); } if (LobbyMembers.Dropped.Count > 0) { text += "\nCan't play here (need More Players 1.0.0):"; for (int l = 0; l < LobbyMembers.Dropped.Count; l++) { text = text + "\n " + LobbyMembers.Dropped[l]; } } DrawBox(text, num); } private static float DrawBox(string text, float y) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown if (style == null) { style = new GUIStyle(GUI.skin.box); style.fontSize = Mathf.Max(14, Screen.height / 45); style.alignment = (TextAnchor)0; style.normal.textColor = Color.white; style.padding = new RectOffset(12, 12, 8, 8); } GUIContent val = new GUIContent(text); Vector2 val2 = style.CalcSize(val); GUI.Box(new Rect(((float)Screen.width - val2.x) / 2f, y, val2.x, val2.y), val, style); return val2.y; } }