Due to update 2.4.3, some mods may no longer function. FixedConfig may be necessary.
Decompiled source of BoplEight v0.1.0
BoplEight.dll
Decompiled 5 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BoplEight.Patches; using BoplFixedMath; using HarmonyLib; using Microsoft.CodeAnalysis; using Steamworks; using Steamworks.Data; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BoplEight")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0")] [assembly: AssemblyProduct("BoplEight")] [assembly: AssemblyTitle("BoplEight")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BoplEight { internal struct StartSlot { public ulong SteamId; public byte Color; public byte Team; public byte Ability1; public byte Ability2; public byte Ability3; public bool HasPlayer { get { if (SteamId == 0L && Ability1 == 0 && Ability2 == 0) { return Ability3 != 0; } return true; } } } internal static class Net8 { public const int HardMaxPlayers = 8; public const int ExtraPacketSize = 64; private const int ExtraSlotOffset = 8; private const int ExtraSlotSize = 13; public static int MaxPlayers = 8; public static readonly StartSlot[] ExtraSlots = new StartSlot[4]; public static ushort ExtraSeq; public static readonly Queue<InputPacketQuad> ExtraInputs = new Queue<InputPacketQuad>(); private static InputPacketQuad currentExtra; private static bool hasCurrentExtra; private static readonly byte[] Magic = new byte[4] { 66, 56, 80, 49 }; public static bool EightPlayerOnline { get { if (GameLobby.isOnlineGame && (Object)(object)SteamManager.instance != (Object)null && SteamManager.instance.connectedPlayers != null) { return SteamManager.instance.connectedPlayers.Count >= 4; } return false; } } public static StartSlot[] GetSlots() { //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_0019: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0133: 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_014d: 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_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) StartRequestPacket startParameters = SteamManager.startParameters; StartSlot[] array = new StartSlot[8] { new StartSlot { SteamId = startParameters.p1_id, Color = startParameters.p1_color, Team = startParameters.p1_team, Ability1 = startParameters.p1_ability1, Ability2 = startParameters.p1_ability2, Ability3 = startParameters.p1_ability3 }, new StartSlot { SteamId = startParameters.p2_id, Color = startParameters.p2_color, Team = startParameters.p2_team, Ability1 = startParameters.p2_ability1, Ability2 = startParameters.p2_ability2, Ability3 = startParameters.p2_ability3 }, new StartSlot { SteamId = startParameters.p3_id, Color = startParameters.p3_color, Team = startParameters.p3_team, Ability1 = startParameters.p3_ability1, Ability2 = startParameters.p3_ability2, Ability3 = startParameters.p3_ability3 }, new StartSlot { SteamId = startParameters.p4_id, Color = startParameters.p4_color, Team = startParameters.p4_team, Ability1 = startParameters.p4_ability1, Ability2 = startParameters.p4_ability2, Ability3 = startParameters.p4_ability3 }, default(StartSlot), default(StartSlot), default(StartSlot), default(StartSlot) }; Array.Copy(ExtraSlots, 0, array, 4, 4); return array; } public static int PlayerCount() { return Math.Min(MaxPlayers, Math.Max(0, (int)SteamManager.startParameters.nrOfPlayers)); } public static void CaptureExtrasFromLobby() { List<SteamConnection> list = (((Object)(object)SteamManager.instance != (Object)null) ? SteamManager.instance.connectedPlayers : null); for (int i = 0; i < 4; i++) { int num = i + 3; if (list != null && num < list.Count && list[num] != null) { SteamConnection val = list[num]; ExtraSlots[i] = new StartSlot { SteamId = val.id.Value, Color = (byte)Mathf.Clamp(val.lobby_color, 0, 255), Team = val.lobby_team, Ability1 = val.lobby_ability1, Ability2 = val.lobby_ability2, Ability3 = val.lobby_ability3 }; } else { ExtraSlots[i] = default(StartSlot); } } } public static void RefreshExtraAbilitiesFromPlayers() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) NamedSpriteList val = (((Object)(object)SteamManager.instance != (Object)null) ? SteamManager.instance.abilityIcons : null); if ((Object)(object)val == (Object)null) { return; } List<Player> list = PlayerHandler.Get().PlayerList(); for (int i = 0; i < 4; i++) { StartSlot startSlot = ExtraSlots[i]; if (startSlot.SteamId == 0L) { continue; } for (int j = 0; j < list.Count; j++) { Player val2 = list[j]; if (val2 != null && val2.steamId.Value == startSlot.SteamId) { startSlot.Ability1 = AbilityIndex(val, val2, 0); startSlot.Ability2 = AbilityIndex(val, val2, 1); startSlot.Ability3 = AbilityIndex(val, val2, 2); break; } } ExtraSlots[i] = startSlot; } } private static byte AbilityIndex(NamedSpriteList icons, Player player, int index) { if (player.Abilities == null || index >= player.Abilities.Count || (Object)(object)player.Abilities[index] == (Object)null) { return 0; } int num = icons.IndexOf(((Object)player.Abilities[index]).name); if (num >= 0) { return (byte)num; } return 0; } public static byte[] BuildExtraPacket(ushort seq, int count) { byte[] array = new byte[64]; Array.Copy(Magic, array, Magic.Length); array[4] = (byte)(seq & 0xFF); array[5] = (byte)(seq >> 8); array[6] = (byte)Mathf.Clamp(count, 0, 4); array[7] = 1; for (int i = 0; i < 4; i++) { int num = 8 + i * 13; StartSlot startSlot = ExtraSlots[i]; for (int j = 0; j < 8; j++) { array[num + j] = (byte)(startSlot.SteamId >> j * 8); } array[num + 8] = startSlot.Color; array[num + 9] = startSlot.Team; array[num + 10] = startSlot.Ability1; array[num + 11] = startSlot.Ability2; array[num + 12] = startSlot.Ability3; } return array; } public static void SendExtraPacket(ushort seq, List<SteamConnection> connections, int count) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (connections == null || connections.Count == 0 || count <= 0) { return; } byte[] array = BuildExtraPacket(seq, count); for (int i = 0; i < connections.Count; i++) { SteamConnection val = connections[i]; if (val != null) { ((Connection)(ref ((ConnectionManager)val).Connection)).SendMessage(array, (SendType)8); } } } public static bool IsExtraPacket(byte[] data, int size) { if (data == null || size != 64) { return false; } for (int i = 0; i < Magic.Length; i++) { if (data[i] != Magic[i]) { return false; } } return true; } public static void ReadExtraPacket(byte[] data) { ExtraSeq = (ushort)(data[4] | (data[5] << 8)); int num = Mathf.Clamp((int)data[6], 0, 4); for (int i = 0; i < 4; i++) { int num2 = 8 + i * 13; ulong num3 = 0uL; for (int j = 0; j < 8; j++) { num3 |= (ulong)data[num2 + j] << j * 8; } ExtraSlots[i] = new StartSlot { SteamId = num3, Color = data[num2 + 8], Team = data[num2 + 9], Ability1 = data[num2 + 10], Ability2 = data[num2 + 11], Ability3 = data[num2 + 12] }; } Plugin.Log.LogInfo((object)$"Received 8P start extras (seq {ExtraSeq}, extra players {num})."); } public static void ResetInputs() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) ExtraInputs.Clear(); currentExtra = default(InputPacketQuad); hasCurrentExtra = false; } public static void ApplyExtraInputs() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (!GameLobby.isOnlineGame || GameLobby.isPlayingAReplay) { return; } List<Player> list = PlayerHandler.Get().PlayerList(); if (list != null && list.Count > 4) { if (ExtraInputs.Count > 0) { currentExtra = ExtraInputs.Dequeue(); hasCurrentExtra = true; } if (hasCurrentExtra) { ApplyInput(5, currentExtra.p1); ApplyInput(6, currentExtra.p2); ApplyInput(7, currentExtra.p3); ApplyInput(8, currentExtra.p4); } } } private static void ApplyInput(int playerId, InputPacket packet) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) Player player = PlayerHandler.Get().GetPlayer(playerId); if (player != null) { player.OverrideInputWithNetworkInput(packet); } } public static void ApplyExtraAbilities() { if (!GameLobby.isOnlineGame) { return; } List<Player> list = PlayerHandler.Get().PlayerList(); NamedSpriteList val = (((Object)(object)SteamManager.instance != (Object)null) ? SteamManager.instance.abilityIcons : null); MethodInfo methodInfo = AccessTools.Method(typeof(SteamManager), "ChangePlayerAbilites", (Type[])null, (Type[])null); if (list == null || (Object)(object)val == (Object)null || methodInfo == null) { return; } int nrOfAbilites = SteamManager.startParameters.nrOfAbilites; for (int i = 0; i < 4; i++) { StartSlot startSlot = ExtraSlots[i]; if (startSlot.SteamId == 0L) { continue; } Player val2 = null; for (int j = 0; j < list.Count; j++) { if (list[j] != null && list[j].Id == 5 + i) { val2 = list[j]; break; } } if (val2 != null) { methodInfo.Invoke(null, new object[6] { val2, startSlot.Ability1, startSlot.Ability2, startSlot.Ability3, nrOfAbilites, val }); } } } } [BepInPlugin("com.bopleight.mod", "Bopl Eight", "0.1.0")] [BepInProcess("BoplBattle.exe")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "com.bopleight.mod"; public const string Version = "0.1.0"; internal static ManualLogSource Log; internal static ConfigEntry<int> MaxPlayersConfig; internal static int MaxPlayers = 8; private Harmony harmony; private void Awake() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; MaxPlayersConfig = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxPlayers", 8, new ConfigDescription("Maximum number of players in a lobby (4-8).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(4, 8), Array.Empty<object>())); MaxPlayers = Mathf.Clamp(MaxPlayersConfig.Value, 4, 8); Net8.MaxPlayers = MaxPlayers; Constants.MAX_PLAYERS = MaxPlayers; Host.recordReplay = false; harmony = new Harmony("com.bopleight.mod"); harmony.PatchAll(Assembly.GetExecutingAssembly()); SceneManager.sceneLoaded += OnSceneLoaded; if (!string.IsNullOrEmpty(Constants.version) && !Constants.version.EndsWith(" [8P]")) { Constants.version += " [8P]"; } Log.LogInfo((object)string.Format("Bopl Eight {0} loaded. Max players: {1}.", "0.1.0", MaxPlayers)); foreach (MethodBase item in from m in harmony.GetPatchedMethods() orderby m.DeclaringType?.FullName + "." + m.Name select m) { Log.LogInfo((object)(" patched " + item.DeclaringType?.FullName + "." + item.Name)); } } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { TeamColorExpander.ExpandAll(); } } } namespace BoplEight.Patches { internal static class GameplayPatches { [HarmonyPatch(typeof(GameSessionHandler), "Init")] private static class GameSessionInitPatch { [HarmonyPrefix] private static void Prefix(GameSessionHandler __instance) { TeamColorExpander.Expand(__instance.teamColors); } } [HarmonyPatch(typeof(GameSessionHandler), "SpawnPlayers")] private static class SpawnPlayersPatch { [HarmonyPrefix] private static bool Prefix(GameSessionHandler __instance) { List<Player> list = PlayerHandler.Get().PlayerList(); if (list == null || list.Count <= 4) { return true; } try { SpawnEight(__instance, list); } catch (Exception ex) { Plugin.Log.LogError((object)("Eight-player SpawnPlayers failed; falling back to vanilla: " + ex)); return true; } return false; } private static void SpawnEight(GameSessionHandler handler, List<Player> players) { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: 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_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: 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_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0134: 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_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_029d: 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_02a7: 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) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: 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_025b: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0238: 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) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0257: 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_020f: 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_0213: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: 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_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0460: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0419: Unknown result type (might be due to invalid IL or missing references) //IL_0420: Unknown result type (might be due to invalid IL or missing references) //IL_051c: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Unknown result type (might be due to invalid IL or missing references) //IL_0402: Unknown result type (might be due to invalid IL or missing references) Traverse.Create((object)handler).Field<bool>("gameInProgress").Value = true; SlimeController[] array = (SlimeController[])(object)new SlimeController[players.Count]; Traverse.Create((object)handler).Field<SlimeController[]>("slimeControllers").Value = array; int[] array2 = (from t in players.Select((Player p) => p.Team).Distinct() orderby t select t).ToArray(); int[] array3 = new int[players.Max((Player p) => p.Team) + 1]; Vec2[] teamSpawns = handler.teamSpawns; if (teamSpawns == null || teamSpawns.Length == 0) { throw new InvalidOperationException("Level has no team spawn points."); } Vec2[] array4 = (Vec2[])(object)new Vec2[array2.Length]; for (int num = 0; num < array4.Length; num++) { array4[num] = teamSpawns[num % teamSpawns.Length]; } Vec2 val = ((teamSpawns.Length >= 4) ? ((teamSpawns[0] + teamSpawns[1] + teamSpawns[2] + teamSpawns[3]) * (Fix)0.25f) : teamSpawns[0]); Fix teammateSpawnSpacing = handler.teammateSpawnSpacing; TeamColors teamColors = handler.teamColors; TeamColorExpander.Expand(teamColors); for (int num2 = 0; num2 < players.Count; num2++) { Player val2 = players[num2]; int num3 = Array.IndexOf(array2, val2.Team); Vec2 val3 = array4[Mathf.Clamp(num3, 0, array4.Length - 1)]; int num4 = array3[val2.Team]++; if (num3 >= teamSpawns.Length) { switch (num4) { case 0: { Vec2 val4 = Vec2.NormalizedSafe(val - val3); if (val4.x == Fix.Zero && val4.y == Fix.Zero) { ((Vec2)(ref val4))..ctor(Fix.One, Fix.Zero); } val3 += val4 * teammateSpawnSpacing * (Fix)1.5f; break; } case 1: val3 -= new Vec2(teammateSpawnSpacing, teammateSpawnSpacing * (Fix)0.5f); break; default: val3 += new Vec2(teammateSpawnSpacing, -(teammateSpawnSpacing * (Fix)0.5f)); break; } } else if (num4 == 1) { val3 -= new Vec2(teammateSpawnSpacing, teammateSpawnSpacing * (Fix)0.5f); } else if (num4 >= 2) { val3 += new Vec2(teammateSpawnSpacing, -(teammateSpawnSpacing * (Fix)0.5f)); } val2.playersAndClonesStillAlive = 1; SlimeController val5 = (array[num2] = FixTransform.InstantiateFixed<SlimeController>(handler.PlayerPrefab, val3)); val5.playerNumber = val2.Id; ((Component)val5).transform.SetParent(handler.playerSpawnsRoot.transform); val5.GetPlayerSprite().sprite = null; ((Renderer)val5.GetPlayerSprite()).material = val2.Color; List<AbilityMonoBehaviour> list = new List<AbilityMonoBehaviour>(); val2.CurrentAbilities = new List<GameObject>(); bool flag = true; for (int num5 = 0; num5 < val2.Abilities.Count; num5++) { if ((Object)(object)val2.Abilities[num5].GetComponent<RandomAbility>() == (Object)null) { flag = false; } } bool flag2 = false; for (int num6 = 0; num6 < val2.Abilities.Count; num6++) { RandomAbility component = val2.Abilities[num6].GetComponent<RandomAbility>(); if ((Object)(object)component != (Object)null) { NamedSprite randomAbilityPrefab = RandomAbility.GetRandomAbilityPrefab(component.abilityIcons, component.abilityIcons_demo); flag2 |= randomAbilityPrefab.isOffensiveAbility; if (flag && !flag2 && num6 == val2.Abilities.Count - 1) { randomAbilityPrefab = RandomAbility.GetRandomAbilityPrefab(component.abilityIcons, component.abilityIcons_demo); } val2.AbilityIcons[num6] = randomAbilityPrefab.sprite; GameObject val6 = FixTransform.InstantiateFixed(randomAbilityPrefab.associatedGameObject, Vec2.zero); val6.SetActive(false); val2.CurrentAbilities.Add(val6); list.Add(val6.GetComponent<AbilityMonoBehaviour>()); } else { GameObject val7 = FixTransform.InstantiateFixed(val2.Abilities[num6], Vec2.zero); val7.SetActive(false); val2.CurrentAbilities.Add(val7); list.Add(val7.GetComponent<AbilityMonoBehaviour>()); } } val5.abilities = list; AbilityReadyIndicator[] array5 = (AbilityReadyIndicator[])(object)new AbilityReadyIndicator[3]; for (int num7 = 0; num7 < 3; num7++) { array5[num7] = Object.Instantiate<GameObject>(handler.AbilityReadyIndicators[num7], handler.playerSpawnsRoot.transform).GetComponent<AbilityReadyIndicator>(); array5[num7].Init(); array5[num7].SetColor(teamColors.teamColors[Mathf.Clamp(val2.Team, 0, teamColors.teamColors.Length - 1)].fill); ((Component)array5[num7]).GetComponent<FollowTransform>().Leader = ((Component)val5).transform; ((Component)array5[num7]).gameObject.SetActive(false); if (num7 < val2.AbilityIcons.Count) { array5[num7].SetSprite(val2.AbilityIcons[num7], true); } } val5.AbilityReadyIndicators = array5; Traverse.Create((object)handler).Field<bool>("gameOver").Value = false; if (val2.IsLocalPlayer) { InputUpdater obj = Object.Instantiate<InputUpdater>(handler.InputUpdaterPrefab); PlayerInput component2 = ((Component)obj).GetComponent<PlayerInput>(); obj.Claim(val2.Id); obj.Init(val2.Id); component2.neverAutoSwitchControlSchemes = true; component2.ActivateInput(); } } Plugin.Log.LogInfo((object)$"Spawned {players.Count} players across {array2.Length} teams."); } } } internal static class TeamColorExpander { private static readonly Color[] ExtraColors = (Color[])(object)new Color[8] { new Color(1f, 0.55f, 0.05f), new Color(1f, 0.3f, 0.6f), new Color(0f, 0.85f, 0.85f), new Color(0.5f, 1f, 0.15f), new Color(1f, 0.84f, 0f), new Color(0.7f, 0.5f, 0.9f), new Color(0.4f, 1f, 0.7f), new Color(1f, 0.5f, 0.31f) }; public static void ExpandAll() { try { TeamColors[] array = Resources.FindObjectsOfTypeAll<TeamColors>(); for (int i = 0; i < array.Length; i++) { Expand(array[i]); } TeamSelector[] array2 = Resources.FindObjectsOfTypeAll<TeamSelector>(); foreach (TeamSelector val in array2) { if ((Object)(object)val != (Object)null) { Expand(val.teams); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Team color expansion scan failed: " + ex.Message)); } } public static void Expand(TeamColors colors) { //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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_008f: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)colors == (Object)null) && colors.teamColors != null && colors.teamColors.Length < Net8.MaxPlayers) { TeamColor[] teamColors = colors.teamColors; TeamColor[] array = (TeamColor[])(object)new TeamColor[Net8.MaxPlayers]; Array.Copy(teamColors, array, teamColors.Length); for (int i = teamColors.Length; i < array.Length; i++) { Color val = ExtraColors[(i - teamColors.Length) % ExtraColors.Length]; array[i] = new TeamColor { team = i, fill = val, border = Darken(val, 0.5f), saturated = Saturate(val, 1.3f) }; } colors.teamColors = array; Plugin.Log.LogInfo((object)$"Expanded TeamColors from {teamColors.Length} to {array.Length}."); } } private static Color Darken(Color color, float factor) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) return new Color(Mathf.Clamp01(color.r * factor), Mathf.Clamp01(color.g * factor), Mathf.Clamp01(color.b * factor), 1f); } private static Color Saturate(Color color, float factor) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //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) float num = default(float); float num2 = default(float); float num3 = default(float); Color.RGBToHSV(color, ref num, ref num2, ref num3); Color result = Color.HSVToRGB(num, Mathf.Clamp01(num2 * factor), Mathf.Clamp01(num3 * 1.1f)); result.a = 1f; return result; } } internal static class InputPatches { private sealed class Snapshot { public int BeforeCount; public readonly Dictionary<int, List<InputPacket>> ExtraInputs = new Dictionary<int, List<InputPacket>>(); public List<InputPacket> LocalInputs; } [HarmonyPatch(typeof(Host), "ProcessNetworkPackets")] private static class ProcessNetworkPacketsPatch { [HarmonyPrefix] private static void Prefix(Host __instance) { try { Queue<InputPacketQuad> queue = InputBufferField?.GetValue(__instance) as Queue<InputPacketQuad>; List<Client> list = ClientsField?.GetValue(__instance) as List<Client>; int num = ((!(LocalPlayerIdField != null)) ? 1 : ((int)LocalPlayerIdField.GetValue(__instance))); if (queue == null || list == null) { pending = null; return; } Snapshot snapshot = new Snapshot { BeforeCount = queue.Count }; for (int i = 0; i < list.Count; i++) { Client val = list[i]; if (val != null && val.PlayerId > 4) { snapshot.ExtraInputs[val.PlayerId] = new List<InputPacket>(val.inputHistory); } } if (num > 4) { Queue<InputPacket> queue2 = SentPacketHistoryField?.GetValue(__instance) as Queue<InputPacket>; snapshot.LocalInputs = ((queue2 != null) ? new List<InputPacket>(queue2) : new List<InputPacket>()); } pending = snapshot; } catch (Exception ex) { pending = null; Plugin.Log.LogError((object)("Input snapshot prefix failed: " + ex)); } } [HarmonyPostfix] private static void Postfix(Host __instance) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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) Snapshot pending = InputPatches.pending; InputPatches.pending = null; if (pending == null) { return; } try { if (!(InputBufferField?.GetValue(__instance) is Queue<InputPacketQuad> queue)) { return; } int num = queue.Count - pending.BeforeCount; for (int i = 0; i < num; i++) { InputPacketQuad quad = default(InputPacketQuad); foreach (KeyValuePair<int, List<InputPacket>> extraInput in pending.ExtraInputs) { List<InputPacket> value = extraInput.Value; if (value.Count > 0) { Assign(ref quad, extraInput.Key - 4, value[0]); value.RemoveAt(0); } } if (pending.LocalInputs != null && pending.LocalInputs.Count > 0) { int num2 = ((!(LocalPlayerIdField != null)) ? 1 : ((int)LocalPlayerIdField.GetValue(__instance))); Assign(ref quad, num2 - 4, pending.LocalInputs[0]); pending.LocalInputs.RemoveAt(0); } Net8.ExtraInputs.Enqueue(quad); } } catch (Exception ex) { Plugin.Log.LogError((object)("Input snapshot postfix failed: " + ex)); } } private static void Assign(ref InputPacketQuad quad, int index, InputPacket packet) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0032: 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) switch (index) { case 1: quad.p1 = packet; break; case 2: quad.p2 = packet; break; case 3: quad.p3 = packet; break; case 4: quad.p4 = packet; break; } } } [HarmonyPatch(typeof(Updater), "TickSimulation")] private static class TickSimulationPatch { [HarmonyPrefix] private static void Prefix() { Net8.ApplyExtraInputs(); } } [HarmonyPatch(typeof(Host), "Init")] private static class HostInitPatch { [HarmonyPostfix] private static void Postfix() { Net8.ResetInputs(); } } private static readonly FieldInfo InputBufferField = AccessTools.Field(typeof(Host), "InputBuffer"); private static readonly FieldInfo ClientsField = AccessTools.Field(typeof(Host), "clients"); private static readonly FieldInfo LocalPlayerIdField = AccessTools.Field(typeof(Host), "localPlayerId"); private static readonly FieldInfo SentPacketHistoryField = AccessTools.Field(typeof(Host), "sentPacketHistory"); private static Snapshot pending; } internal static class LobbyCreator { public static async Task<bool> CreateAsync(SteamManager manager, int maxPlayers) { try { Lobby? val = await SteamMatchmaking.CreateLobbyAsync(maxPlayers); if (!val.HasValue) { Plugin.Log.LogError((object)"Steam returned no lobby; lobby creation failed."); return false; } manager.currentLobby = val.Value; ref Lobby currentLobby = ref manager.currentLobby; SteamId steamId = SteamClient.SteamId; ((Lobby)(ref currentLobby)).SetData("accId", ((int)((SteamId)(ref steamId)).AccountId).ToString()); ((Lobby)(ref manager.currentLobby)).SetData("version", Constants.version); ((Lobby)(ref manager.currentLobby)).SetFriendsOnly(); ((Lobby)(ref manager.currentLobby)).SetJoinable(true); Plugin.Log.LogInfo((object)$"Created Steam lobby with {((Lobby)(ref manager.currentLobby)).MaxMembers} member slots."); return true; } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to create multiplayer lobby: " + ex)); return false; } } } internal static class LobbyPatches { [HarmonyPatch(typeof(SteamManager), "CreateFriendLobby")] private static class CreateFriendLobbyPatch { [HarmonyPrefix] private static bool Prefix(SteamManager __instance, ref Task<bool> __result) { __result = LobbyCreator.CreateAsync(__instance, Plugin.MaxPlayers); return false; } } [HarmonyPatch(typeof(SteamManager), "HostGame")] private static class HostGamePatch { [HarmonyPrefix] private static void Prefix(SteamManager __instance) { try { Net8.CaptureExtrasFromLobby(); FieldInfo fieldInfo = AccessTools.Field(typeof(SteamManager), "nextStartGameSeq"); ushort num = (ushort)((!(fieldInfo != null)) ? 1 : ((ushort)fieldInfo.GetValue(__instance))); Net8.ExtraSeq = num; int num2 = Mathf.Clamp(__instance.connectedPlayers.Count - 3, 0, 4); Net8.SendExtraPacket(num, __instance.connectedPlayers, num2); Plugin.Log.LogInfo((object)$"Hosting with {__instance.connectedPlayers.Count + 1} players; sent extras for {num2} (seq {num})."); } catch (Exception ex) { Plugin.Log.LogError((object)("HostGame extra-slot prefix failed: " + ex)); } } } [HarmonyPatch(typeof(SteamManager), "HostNextLevel")] private static class HostNextLevelPatch { [HarmonyPrefix] private static void Prefix(SteamManager __instance) { try { Net8.CaptureExtrasFromLobby(); Net8.RefreshExtraAbilitiesFromPlayers(); int count = Mathf.Clamp(__instance.connectedPlayers.Count - 3, 0, 4); Net8.SendExtraPacket(SteamManager.startParameters.seqNum, __instance.connectedPlayers, count); } catch (Exception ex) { Plugin.Log.LogError((object)("HostNextLevel extra-slot prefix failed: " + ex)); } } } [HarmonyPatch(typeof(SteamSocket), "OnMessage")] private static class ExtraStartPacketPatch { [HarmonyPrefix] private static bool Prefix(NetIdentity identity, IntPtr data, int size) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (size != 64) { return true; } try { byte[] array = new byte[size]; Marshal.Copy(data, array, 0, size); if (!Net8.IsExtraPacket(array, size)) { return true; } SteamManager instance = SteamManager.instance; if ((Object)(object)instance == (Object)null || !((Lobby)(ref instance.currentLobby)).IsOwnedBy(((NetIdentity)(ref identity)).SteamId)) { Plugin.Log.LogWarning((object)"Ignored an 8P start-extras packet that did not come from the lobby owner."); return false; } Net8.ReadExtraPacket(array); return false; } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to read 8P start extras: " + ex)); return false; } } } [HarmonyPatch(typeof(SteamManager), "InitNetworkClient")] private static class InitNetworkClientPatch { [HarmonyPrefix] private static bool Prefix(SteamManager __instance) { try { Init(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("8P InitNetworkClient failed: " + ex)); } return false; } private static void Init(SteamManager manager) { //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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_0121: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown StartRequestPacket startParameters = SteamManager.startParameters; int num = Math.Min(Net8.MaxPlayers, startParameters.nrOfPlayers); StartSlot[] slots = Net8.GetSlots(); ulong value = SteamClient.SteamId.Value; int num2 = 1; for (int i = 0; i < num; i++) { if (slots[i].SteamId == value) { num2 = i + 1; break; } } List<Client> list = new List<Client>(); for (int j = 0; j < manager.connectedPlayers.Count; j++) { SteamConnection val = manager.connectedPlayers[j]; if (val == null) { continue; } int num3 = 0; for (int k = 0; k < num; k++) { if (slots[k].SteamId == val.id.Value) { num3 = k + 1; break; } } if (num3 > 0 && num3 != num2) { list.Add(new Client(num3, val)); } } manager.networkClient.Init(list, num2, startParameters.currentLevel, manager.startFrameBuffer, manager.checkForDesyncs); SteamManager.networkClientHandle = manager.networkClient; Plugin.Log.LogInfo((object)$"Network client initialized: local player {num2}, {list.Count} remote clients, {startParameters.nrOfPlayers} total players."); } } [HarmonyPatch(typeof(CharacterSelectHandler_online), "ForceStartGame")] private static class ForceStartGamePatch { [HarmonyPrefix] private static bool Prefix(PlayerColors pcs) { try { StartMatch(pcs); } catch (Exception ex) { Plugin.Log.LogError((object)("8P ForceStartGame failed: " + ex)); } return false; } private static void StartMatch(PlayerColors pcs) { //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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) StartRequestPacket startParameters = SteamManager.startParameters; Updater.ReInit(); Updater.InitSeed(startParameters.seed); int num = Math.Min(Net8.MaxPlayers, startParameters.nrOfPlayers); if (num <= 0) { Plugin.Log.LogError((object)"Start request had no players; aborting."); return; } FieldInfo fieldInfo = AccessTools.Field(typeof(CharacterSelectHandler_online), "selfRef"); CharacterSelectHandler_online val = (CharacterSelectHandler_online)((fieldInfo != null) ? /*isinst with value type is only supported in some contexts*/: null); PlayerColors val2 = pcs ?? val?.playerColors; NamedSpriteList val3 = (((Object)(object)SteamManager.instance != (Object)null) ? SteamManager.instance.abilityIcons : null); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { Plugin.Log.LogError((object)"Could not resolve PlayerColors or ability icons; aborting start."); return; } StartSlot[] slots = Net8.GetSlots(); List<Player> list = new List<Player>(num); for (int i = 0; i < num; i++) { StartSlot slot = slots[i]; if (slot.Ability1 != 0 || slot.Ability2 != 0 || slot.Ability3 != 0) { list.Add(NewPlayer(i + 1, slot, val2, val3, startParameters.nrOfAbilites)); } } if (list.Count == 0) { Plugin.Log.LogError((object)"No valid players were present in the start request; aborting."); return; } Player val4 = null; if (GameLobby.isPlayingAReplay) { val4 = list[0]; } else { ulong value = SteamClient.SteamId.Value; for (int j = 0; j < list.Count; j++) { if (list[j].steamId.Value == value) { val4 = list[j]; break; } } } if (val4 == null) { Plugin.Log.LogWarning((object)"Local Steam ID was not in the start slots; falling back to player 1."); val4 = list[0]; } val4.IsLocalPlayer = true; val4.inputDevice = CharacterSelectHandler_online.localPlayerInit.inputDevice; val4.UsesKeyboardAndMouse = CharacterSelectHandler_online.localPlayerInit.usesKeyboardMouse; val4.CustomKeyBinding = CharacterSelectHandler_online.localPlayerInit.keybindOverride; CharacterSelectHandler_online.startButtonAvailable = false; PlayerHandler.Get().SetPlayerList(list); Plugin.Log.LogInfo((object)$"Starting match with {list.Count} players across {CountTeams(list)} teams."); 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); } } private static Player NewPlayer(int id, StartSlot slot, PlayerColors colors, NamedSpriteList icons, int nrOfAbilities) { //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_000c: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown Player val = new Player { Id = id, Team = (byte)Mathf.Clamp((int)slot.Team, 0, Net8.MaxPlayers - 1), steamId = SteamId.op_Implicit(slot.SteamId), IsLocalPlayer = false }; int num = ((colors.Length > 0) ? (slot.Color % colors.Length) : 0); val.Color = colors.playerColors[num].playerMaterial; if (nrOfAbilities > 0) { AddAbility(val, icons, slot.Ability1); } if (nrOfAbilities > 1) { AddAbility(val, icons, slot.Ability2); } if (nrOfAbilities > 2) { AddAbility(val, icons, slot.Ability3); } return val; } private static void AddAbility(Player player, NamedSpriteList icons, byte index) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (icons.sprites != null && index < icons.sprites.Count) { NamedSprite val = icons.sprites[index]; player.Abilities.Add(val.associatedGameObject); player.AbilityIcons.Add(val.sprite); } } private static int CountTeams(List<Player> players) { HashSet<int> hashSet = new HashSet<int>(); for (int i = 0; i < players.Count; i++) { hashSet.Add(players[i].Team); } return hashSet.Count; } } [HarmonyPatch(typeof(SteamManager), "ForceLoadNextLevel")] private static class ForceLoadNextLevelPatch { [HarmonyPostfix] private static void Postfix() { try { Net8.ApplyExtraAbilities(); } catch (Exception ex) { Plugin.Log.LogError((object)("Applying extra players' next-level abilities failed: " + ex)); } } } [HarmonyPatch(typeof(printText), "Awake")] private static class VersionSuffixPatch { [HarmonyPostfix] private static void Postfix() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (Constants.version == null) { return; } if (!Constants.version.EndsWith(" [8P]")) { Constants.version += " [8P]"; } try { SteamManager instance = SteamManager.instance; if (SteamClient.IsValid && (Object)(object)instance != (Object)null && ((Lobby)(ref instance.currentLobby)).Id.Value != 0L && ((Lobby)(ref instance.currentLobby)).IsOwnedBy(SteamClient.SteamId)) { ((Lobby)(ref instance.currentLobby)).SetData("version", Constants.version); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not refresh lobby version: " + ex.Message)); } } } } internal static class UiPatches { [HarmonyPatch(typeof(CharacterSelectHandler), "Awake")] private static class CharacterSelectAwakePatch { [HarmonyPostfix] private static void Postfix() { TeamColorExpander.ExpandAll(); } } [HarmonyPatch(typeof(CharacterSelectHandler_online), "Start")] private static class OnlineStartPatch { [HarmonyPostfix] private static void Postfix(CharacterSelectHandler_online __instance) { try { TeamColorExpander.ExpandAll(); OnlineUi.Expand(__instance); OnlineUi.AssignLocalTeam(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("Expanding online character-select UI failed: " + ex)); } } } [HarmonyPatch(typeof(CSBox_online), "Init")] private static class OnlineBoxInitPatch { [HarmonyPostfix] private static void Postfix(CSBox_online __instance, SteamConnection targetPlayer) { try { TeamColorExpander.Expand(Traverse.Create((object)__instance).Field<TeamColors>("teamColors").Value); OnlineUi.AssignTeam(targetPlayer); } catch (Exception ex) { Plugin.Log.LogError((object)("Online box team assignment failed: " + ex)); } } } [HarmonyPatch(typeof(CSBox_online), "Update")] private static class OnlineBoxUpdatePatch { [HarmonyPrefix] private static void Prefix(CSBox_online __instance) { SteamConnection connectedPlayer = __instance.connectedPlayer; if (connectedPlayer != null && connectedPlayer.lobby_team >= Net8.MaxPlayers) { connectedPlayer.lobby_team = 0; } } } [HarmonyPatch(typeof(CharacterSelectHandler), "IsColorTaken")] private static class ColorUniquenessPatch { [HarmonyPostfix] private static void Postfix(ref bool __result) { if (__result && GameLobby.isOnlineGame && !((Object)(object)SteamManager.instance == (Object)null) && SteamManager.instance.connectedPlayers.Count >= 4) { __result = false; } } } [HarmonyPatch(typeof(PlayerAverageCamera), "Start")] private static class CameraPatch { [HarmonyPostfix] private static void Postfix(PlayerAverageCamera __instance) { int num = PlayerHandler.Get().NumberOfPlayers(); if (num > 4) { Traverse obj = Traverse.Create((object)__instance); float value = obj.Field<float>("MAX_ZOOM").Value; float value2 = obj.Field<float>("MIN_ZOOM").Value; float value3 = obj.Field<float>("extraZoomRoom").Value; float num2 = Mathf.Lerp(1.2f, 1.6f, (float)(num - 4) / 4f); obj.Field<float>("MAX_ZOOM").Value = value * num2; obj.Field<float>("MIN_ZOOM").Value = value2 * 1.05f; obj.Field<float>("extraZoomRoom").Value = value3 + (float)(num - 4) * 0.25f; } } } [HarmonyPatch(typeof(HandleAbilitySelectUI), "Init")] private static class AbilitySelectSpacingPatch { [HarmonyPrefix] private static void Prefix(HandleAbilitySelectUI __instance, ref float __state) { Traverse<float> val = Traverse.Create((object)__instance).Field<float>("Separation"); __state = val.Value; int num = PlayerHandler.Get().NumberOfPlayers(); if (num > 4) { val.Value = Mathf.Max(48f, __state * (4f / (float)num)); } } [HarmonyPostfix] private static void Postfix(HandleAbilitySelectUI __instance, float __state) { Traverse.Create((object)__instance).Field<float>("Separation").Value = __state; } } [HarmonyPatch(typeof(CharacterStatsList), "OnEnable")] private static class CharacterStatsListPatch { [HarmonyPrefix] private static void Prefix(CharacterStatsList __instance) { int num = PlayerHandler.Get().NumberOfPlayers(); if (num > 4) { EnsureCapacity(__instance, "winnersOfDraw", num); } } private static void EnsureCapacity(CharacterStatsList owner, string fieldName, int required) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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) Traverse<Image[]> val = Traverse.Create((object)owner).Field<Image[]>(fieldName); Image[] value = val.Value; if (value == null || value.Length == 0 || value.Length >= required) { return; } List<Image> list = value.ToList(); Image val2 = value[^1]; RectTransform component = ((Component)val2).GetComponent<RectTransform>(); for (int i = list.Count; i < required; i++) { GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, ((Component)val2).transform.parent); ((Object)val3).name = ((Object)((Component)val2).gameObject).name + "_P" + (i + 1); Image component2 = val3.GetComponent<Image>(); if (!((Object)(object)component2 == (Object)null)) { RectTransform component3 = val3.GetComponent<RectTransform>(); if ((Object)(object)component3 != (Object)null && (Object)(object)component != (Object)null) { component3.anchoredPosition = component.anchoredPosition + new Vector2(75f, 0f) * (float)(i - (value.Length - 1)); } val3.SetActive(false); list.Add(component2); } } val.Value = list.ToArray(); } } } internal static class OnlineUi { public static void Expand(CharacterSelectHandler_online handler) { CSBox_online[] networkPlayerBoxes = handler.networkPlayerBoxes; if (networkPlayerBoxes == null || networkPlayerBoxes.Length == 0) { return; } int originalCount = networkPlayerBoxes.Length; List<CSBox_online> list = networkPlayerBoxes.ToList(); CSBox_online val = networkPlayerBoxes[^1]; Transform parent = ((Component)val).transform.parent; for (int i = networkPlayerBoxes.Length; i < Net8.MaxPlayers; i++) { GameObject obj = Object.Instantiate<GameObject>(((Component)val).gameObject, parent); ((Object)obj).name = ((Object)((Component)val).gameObject).name + "_P" + (i + 1); CSBox_online component = obj.GetComponent<CSBox_online>(); if (!((Object)(object)component == (Object)null)) { component.connectedPlayer = null; component.isVisible = false; Traverse.Create((object)component).Field<bool>("choosingTextIsVisible").Value = true; list.Add(component); } } handler.networkPlayerBoxes = list.ToArray(); Image[] loadingCircles = handler.loadingCircles; if (loadingCircles != null && loadingCircles.Length != 0 && loadingCircles.Length < Net8.MaxPlayers) { List<Image> list2 = loadingCircles.ToList(); Image val2 = loadingCircles[^1]; for (int j = loadingCircles.Length; j < Net8.MaxPlayers; j++) { GameObject obj2 = Object.Instantiate<GameObject>(((Component)val2).gameObject, ((Component)val2).transform.parent); ((Object)obj2).name = ((Object)((Component)val2).gameObject).name + "_P" + (j + 1); Image component2 = obj2.GetComponent<Image>(); if ((Object)(object)component2 != (Object)null) { ((Behaviour)component2).enabled = false; list2.Add(component2); } } handler.loadingCircles = list2.ToArray(); } Layout(list, originalCount); } private static void Layout(List<CSBox_online> boxes, int originalCount) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0103: 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) RectTransform[] array = (from box in boxes select (!((Object)(object)box != (Object)null)) ? null : ((Component)box).GetComponent<RectTransform>() into rect where (Object)(object)rect != (Object)null select rect).ToArray(); if (array.Length >= boxes.Count && originalCount > 0) { float num = float.MaxValue; float num2 = float.MinValue; float y = array[0].anchoredPosition.y; for (int num3 = 0; num3 < originalCount && num3 < array.Length; num3++) { num = Mathf.Min(num, array[num3].anchoredPosition.x); num2 = Mathf.Max(num2, array[num3].anchoredPosition.x); y = array[num3].anchoredPosition.y; } for (int num4 = 0; num4 < array.Length; num4++) { float num5 = ((array.Length > 1) ? ((float)num4 / (float)(array.Length - 1)) : 0.5f); array[num4].anchoredPosition = new Vector2(Mathf.Lerp(num, num2, num5), y); ((Transform)array[num4]).localScale = Vector3.one * 0.62f; } } } public static void AssignTeam(SteamConnection target) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (target == null || (Object)(object)SteamManager.instance == (Object)null) { return; } List<SteamConnection> connectedPlayers = SteamManager.instance.connectedPlayers; bool[] array = new bool[Net8.MaxPlayers]; for (int i = 0; i < connectedPlayers.Count; i++) { SteamConnection val = connectedPlayers[i]; if (val != null && val != target) { int lobby_team = val.lobby_team; if (lobby_team >= 0 && lobby_team < array.Length) { array[lobby_team] = true; } } } if (((Lobby)(ref SteamManager.instance.currentLobby)).IsOwnedBy(target.id)) { target.lobby_team = 0; return; } for (int j = 0; j < array.Length; j++) { if (!array[j]) { target.lobby_team = (byte)j; return; } } target.lobby_team = 0; } public static void AssignLocalTeam(CharacterSelectHandler_online handler) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) CharacterSelectBox characterSelectBox = handler.characterSelectBox; if ((Object)(object)characterSelectBox == (Object)null || (Object)(object)SteamManager.instance == (Object)null) { return; } List<SelectableMonoBehaviour> value = Traverse.Create((object)characterSelectBox).Field<List<SelectableMonoBehaviour>>("selectables").Value; if (value == null || value.Count < 2) { return; } SelectableMonoBehaviour obj = value[1]; TeamSelector val = (TeamSelector)(object)((obj is TeamSelector) ? obj : null); if ((Object)(object)val == (Object)null) { return; } List<SteamConnection> connectedPlayers = SteamManager.instance.connectedPlayers; bool flag = ((Lobby)(ref SteamManager.instance.currentLobby)).IsOwnedBy(SteamClient.SteamId); int team = characterSelectBox.playerInit.team; bool[] array = new bool[Net8.MaxPlayers]; for (int i = 0; i < connectedPlayers.Count; i++) { SteamConnection val2 = connectedPlayers[i]; if (val2 != null) { int lobby_team = val2.lobby_team; if (lobby_team >= 0 && lobby_team < array.Length) { array[lobby_team] = true; } } } if (!flag && team >= 0 && team < Net8.MaxPlayers && !array[team]) { return; } int num = -1; if (flag && !array[0]) { num = 0; } else { for (int j = 0; j < array.Length; j++) { if (!array[j]) { num = j; break; } } } if (num >= 0) { ((SelectableMonoBehaviour)val).Select(num); } } } }