using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using HarmonyLib; using Il2CppCS.CorePlatform; using Il2CppCS.CorePlatform.Utils.Data; using Il2CppCoreNet; using Il2CppCoreNet.Components.Client; using Il2CppCoreNet.Contexts; using Il2CppCostumes; using Il2CppFemur; using Il2CppGB.Core.Loading; using Il2CppGB.NetworkedInput; using Il2CppGB.Platform.Lobby; using Il2CppGB.Platform.Lobby.Messages; using Il2CppGB.Platform.Lobby.Utils; using Il2CppGB.UI.Beasts; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Reflection; using Il2CppTMPro; using MelonLoader; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using ProCon; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Networking; using UnityEngine.SceneManagement; using UnityEngine.TextCore.LowLevel; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(ProConMod), "ProCon", "1.0.0", "AxisGames", null)] [assembly: MelonGame("Boneloaf", "Gang Beasts")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.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 ProCon { internal static class Badge { private static GameObject badge; private static TMP_Text text; public static void Tick() { string text = Session.BadgeLine(); if ((Object)(object)badge == (Object)null) { if (text == null || (Object)(object)MenuFont.Font == (Object)null) { return; } Build(); } badge.SetActive(text != null); if (text != null) { Badge.text.text = text; } } private static void Build() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ProCon Badge"); Object.DontDestroyOnLoad((Object)(object)val); Canvas obj = val.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 5000; CanvasScaler obj2 = val.AddComponent(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = new Vector2(1920f, 1080f); obj2.matchWidthOrHeight = 0.5f; badge = new GameObject("Badge"); badge.transform.SetParent(val.transform, false); RectTransform obj3 = badge.AddComponent(); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(0f, 1f); obj3.pivot = val2; Vector2 anchorMin = (obj3.anchorMax = val2); obj3.anchorMin = anchorMin; obj3.anchoredPosition = new Vector2(28f, -22f); obj3.sizeDelta = new Vector2(700f, 70f); text = (TMP_Text)(object)badge.AddComponent(); text.font = MenuFont.Font; text.fontSharedMaterial = MenuFont.OutlinedMaterial; text.fontSize = 40f; ((Graphic)text).color = new Color(1f, 0.78f, 0.05f); text.alignment = (TextAlignmentOptions)513; text.enableWordWrapping = false; ((Graphic)text).raycastTarget = false; } } internal static class Clipboard { private const uint CF_UNICODETEXT = 13u; [DllImport("user32.dll")] private static extern bool OpenClipboard(IntPtr owner); [DllImport("user32.dll")] private static extern bool CloseClipboard(); [DllImport("user32.dll")] private static extern IntPtr GetClipboardData(uint format); [DllImport("user32.dll")] private static extern bool EmptyClipboard(); [DllImport("user32.dll")] private static extern IntPtr SetClipboardData(uint format, IntPtr h); [DllImport("kernel32.dll")] private static extern IntPtr GlobalLock(IntPtr h); [DllImport("kernel32.dll")] private static extern bool GlobalUnlock(IntPtr h); [DllImport("kernel32.dll")] private static extern IntPtr GlobalAlloc(uint flags, UIntPtr bytes); public static string Get() { if (!OpenClipboard(IntPtr.Zero)) { return ""; } try { IntPtr clipboardData = GetClipboardData(13u); if (clipboardData == IntPtr.Zero) { return ""; } IntPtr ptr = GlobalLock(clipboardData); try { return Marshal.PtrToStringUni(ptr) ?? ""; } finally { GlobalUnlock(clipboardData); } } finally { CloseClipboard(); } } public static void Set(string text) { if (!OpenClipboard(IntPtr.Zero)) { return; } try { EmptyClipboard(); IntPtr h = GlobalAlloc(2u, (UIntPtr)(ulong)((text.Length + 1) * 2)); IntPtr destination = GlobalLock(h); Marshal.Copy((text + "\0").ToCharArray(), 0, destination, text.Length + 1); GlobalUnlock(h); SetClipboardData(13u, h); } finally { CloseClipboard(); } } } internal static class ConsoleFix { private const int STD_INPUT_HANDLE = -10; private const uint ENABLE_QUICK_EDIT_MODE = 64u; private const uint ENABLE_EXTENDED_FLAGS = 128u; [DllImport("kernel32.dll")] private static extern IntPtr GetStdHandle(int handle); [DllImport("kernel32.dll")] private static extern bool GetConsoleMode(IntPtr h, out uint mode); [DllImport("kernel32.dll")] private static extern bool SetConsoleMode(IntPtr h, uint mode); public static void DisableQuickEdit() { try { IntPtr stdHandle = GetStdHandle(-10); if (GetConsoleMode(stdHandle, out var mode)) { SetConsoleMode(stdHandle, (mode & 0xFFFFFFBFu) | 0x80); } } catch { } } } internal static class LobbySync { private class Remote { public BaseUserInfo User; public int Master; public readonly Dictionary Beasts = new Dictionary(); public readonly HashSet Spawned = new HashSet(); } public const byte Message = 6; public static readonly ConcurrentQueue<(ulong from, byte[] data)> Incoming = new ConcurrentQueue<(ulong, byte[])>(); private static readonly Dictionary remotes = new Dictionary(); private static readonly Dictionary> latest = new Dictionary>(); private static float sendTimer; private static int nextMaster; public static bool Active; public static void Tick(bool hosting) { //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) Scene activeScene = SceneManager.GetActiveScene(); bool flag = ((Scene)(ref activeScene)).name == "Menu"; if (!Active || !flag) { if (remotes.Count > 0) { Clear(); } DrainIncoming(apply: false); return; } DrainIncoming(apply: true); sendTimer -= Time.unscaledDeltaTime; if (sendTimer > 0f) { return; } sendTimer = 0.4f; List<(int, byte[])> list = LocalBeasts(); if (hosting) { foreach (ulong item in Relay.FriendIds()) { List<(ulong, int, byte[])> list2 = new List<(ulong, int, byte[])>(); foreach (var item2 in list) { list2.Add((SteamNet.MySteamId, item2.Item1, item2.Item2)); } foreach (KeyValuePair> item3 in latest) { if (item3.Key != item) { foreach (var item4 in item3.Value) { list2.Add((item3.Key, item4.Item1, item4.Item2)); } } } Relay.SendLobby(item, Pack(list2)); } return; } List<(ulong, int, byte[])> list3 = new List<(ulong, int, byte[])>(); foreach (var item5 in list) { list3.Add((SteamNet.MySteamId, item5.Item1, item5.Item2)); } Relay.SendLobby(0uL, Pack(list3)); } private static List<(int ctrl, byte[] data)> LocalBeasts() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) List<(int, byte[])> list = new List<(int, byte[])>(); LobbyManager instance = LobbyManager.Instance; LocalBeastSetupTracker val = ((instance != null) ? instance.LocalBeasts : null); object obj; if (instance == null) { obj = null; } else { LocalBeastMessageSender beastMessageSender = instance.BeastMessageSender; obj = ((beastMessageSender != null) ? beastMessageSender._beastMessages : null); } Il2CppReferenceArray val2 = (Il2CppReferenceArray)obj; if ((Object)(object)val == (Object)null || val2 == null) { return list; } BeastMenuState state = Object.FindObjectOfType(); for (int i = 0; i < ((Il2CppArrayBase)(object)val2).Length && i < ((Il2CppArrayBase)(object)val.PlayerInfo).Length; i++) { LocalPlayerInfomationCache val3 = ((Il2CppArrayBase)(object)val.PlayerInfo)[i]; if (val3 == null || (int)val3.CurrentState == 0) { continue; } BeastInfoMesssage obj2 = ((Il2CppArrayBase)(object)val2)[i]; BeastInfo val4 = ((obj2 != null) ? obj2.Info : null); if (val4 != null) { BeastInfo val5 = new BeastInfo(); val5.Copy(val4); val5.SetControllerID(i); val5.SetState(val3.CurrentState); if (val3.ColourIndex >= 0) { val5.SetColour(val3.ColourIndex); } val5.SetTeam(val3.TeamIndex); CostumeSaveEntry val6 = ShownCostume(state, i); if (val6 != null) { val5.SetCostume(val6); } list.Add((i, ToBytes(val5))); } } return list; } private static CostumeSaveEntry ShownCostume(BeastMenuState state, int playerID) { try { Il2CppReferenceArray val = ((state != null) ? state._pointStates : null); if (val == null) { return null; } foreach (PointState item in (Il2CppArrayBase)(object)val) { if (((item != null) ? item._linkedLocal : null) != null && item._linkedLocal.PlayerID == playerID) { return item._costumeCache; } } } catch { } return null; } private static void DrainIncoming(bool apply) { (ulong, byte[]) result; while (Incoming.TryDequeue(out result)) { if (apply) { try { Apply(result.Item1, result.Item2); } catch (Exception ex) { MelonLogger.Warning("Lobby sync: " + ex.Message); } } } } private static void Apply(ulong from, byte[] data) { if (data.Length == 0) { FriendLeft(from); return; } List<(ulong, int, byte[])> list = Unpack(data); ulong mySteamId = SteamNet.MySteamId; if (Session.IsHosting) { List<(int, byte[])> list2 = new List<(int, byte[])>(); foreach (var item in list) { if (item.Item1 == from) { list2.Add((item.Item2, item.Item3)); } } latest[from] = list2; SyncOwner(from, list2); return; } Dictionary> dictionary = new Dictionary>(); foreach (var item2 in list) { if (item2.Item1 != mySteamId) { if (!dictionary.TryGetValue(item2.Item1, out var value)) { value = (dictionary[item2.Item1] = new List<(int, byte[])>()); } value.Add((item2.Item2, item2.Item3)); } } foreach (KeyValuePair> item3 in dictionary) { SyncOwner(item3.Key, item3.Value); } foreach (ulong item4 in new List(remotes.Keys)) { if (!dictionary.ContainsKey(item4)) { RemoveOwner(item4); } } } public static void FriendLeft(ulong id) { latest.Remove(id); if (remotes.ContainsKey(id)) { RemoveOwner(id); } } private static void SyncOwner(ulong owner, List<(int ctrl, byte[] data)> beasts) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Invalid comparison between Unknown and I4 LobbyManager instance = LobbyManager.Instance; OnlineBeastSetupTracker val = ((instance != null) ? instance.OnlineBeasts : null); BeastMenuManager val2 = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { return; } if (!remotes.TryGetValue(owner, out var value)) { value = new Remote { User = new BaseUserInfo(owner, (PlatformKeys)1, SteamNet.Name(owner)), Master = BeastUtils.PlayerID_Lobby + 8 * (nextMaster++ % 24) }; val.OnPlayerJoined(value.User, value.Master); remotes[owner] = value; MelonLogger.Msg("Lobby: " + value.User.userName + " is in the lobby."); } HashSet hashSet = new HashSet(); foreach (var (num, array) in beasts) { hashSet.Add(num); if (value.Beasts.TryGetValue(num, out var value2) && Same(value2, array)) { continue; } value.Beasts[num] = array; BeastInfo val3 = new BeastInfo(); if (!val3.Deserialize(new DataReader(Il2CppStructArray.op_Implicit(array), true))) { continue; } val3.SetControllerID(num); val.ForceUpdateBeast(value.User, val3); int num2 = value.Master + num; bool flag = (int)val3.State > 0; if (flag && value.Spawned.Add(num)) { if (val2 != null) { val2.SpawnBeast(num2, Math.Max(0, val3.Team)); } } else if (!flag && value.Spawned.Remove(num) && val2 != null) { val2.DespawnBeast(num2); } } foreach (int item in new List(value.Beasts.Keys)) { if (!hashSet.Contains(item)) { value.Beasts.Remove(item); Hide(value, item, val, val2); } } } private static void Hide(Remote r, int ctrl, OnlineBeastSetupTracker tracker, BeastMenuManager menu) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown BeastInfo val = new BeastInfo(); val.SetControllerID(ctrl); val.SetState((PlayerState)0); try { if (tracker != null) { tracker.ForceUpdateBeast(r.User, val); } } catch { } if (r.Spawned.Remove(ctrl) && menu != null) { menu.DespawnBeast(r.Master + ctrl); } } private static void RemoveOwner(ulong owner) { if (!remotes.TryGetValue(owner, out var value)) { return; } LobbyManager instance = LobbyManager.Instance; OnlineBeastSetupTracker val = ((instance != null) ? instance.OnlineBeasts : null); BeastMenuManager val2 = Object.FindObjectOfType(); foreach (int item in new List(value.Spawned)) { try { if (val2 != null) { val2.DespawnBeast(value.Master + item); } } catch { } } try { if (val != null) { val.OnPlayerLeft(value.User); } } catch { } remotes.Remove(owner); MelonLogger.Msg("Lobby: " + value.User.userName + " left the lobby."); } public static void Clear() { foreach (ulong item in new List(remotes.Keys)) { RemoveOwner(item); } remotes.Clear(); latest.Clear(); nextMaster = 0; } private static byte[] Pack(List<(ulong owner, int ctrl, byte[] data)> beasts) { int num = 2; foreach (var beast in beasts) { num += 11 + beast.data.Length; } byte[] array = new byte[num]; array[0] = 6; array[1] = (byte)beasts.Count; int num2 = 2; foreach (var (value, num3, array2) in beasts) { BitConverter.GetBytes(value).CopyTo(array, num2); num2 += 8; array[num2++] = (byte)num3; BitConverter.GetBytes((ushort)array2.Length).CopyTo(array, num2); num2 += 2; array2.CopyTo(array, num2); num2 += array2.Length; } return array; } private static List<(ulong owner, int ctrl, byte[] data)> Unpack(byte[] buf) { List<(ulong, int, byte[])> list = new List<(ulong, int, byte[])>(); if (buf.Length < 2 || buf[0] != 6) { return list; } int num = buf[1]; int num2 = 2; for (int i = 0; i < num; i++) { if (num2 + 11 > buf.Length) { break; } ulong item = BitConverter.ToUInt64(buf, num2); num2 += 8; int item2 = buf[num2++]; int num3 = BitConverter.ToUInt16(buf, num2); num2 += 2; if (num2 + num3 > buf.Length) { break; } byte[] array = new byte[num3]; Array.Copy(buf, num2, array, 0, num3); num2 += num3; list.Add((item, item2, array)); } return list; } private static byte[] ToBytes(BeastInfo info) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown DataWriter val = new DataWriter(2048); info.Serialize(val); Il2CppStructArray dataBuffer = ((DataStream)val).DataBuffer; byte[] array = new byte[Math.Min(((DataStream)val).DataSize, ((Il2CppArrayBase)(object)dataBuffer).Length)]; for (int i = 0; i < array.Length; i++) { array[i] = ((Il2CppArrayBase)(object)dataBuffer)[i]; } return array; } private static bool Same(byte[] a, byte[] b) { if (a.Length != b.Length) { return false; } for (int i = 0; i < a.Length; i++) { if (a[i] != b[i]) { return false; } } return true; } } internal static class MainMenu { private class Anim { public Button Button; public RectTransform Rt; public TMP_Text Text; public float Scale = 1f; public float Vel; public float Hover; public float Enter = 1f; public float Delay; public float Punch; public float Seed; } private const string SectionPath = "Managers/Menu/Main Menu/Canvas/Main Menu/TextSection"; private static GameObject section; private static GameObject template; private static GameObject pcHome; private static GameObject pcJoin; private static GameObject current; private static TMP_Text codeLabel; private static TMP_Text hintLabel; private static string typed = ""; private static float caretTimer; private static readonly List anims = new List(); private static bool wasVisible; private static Vector2 lastMouse; public static bool InProCon { get { if ((Object)(object)current != (Object)null) { return (Object)(object)current != (Object)(object)section; } return false; } } public static bool OnMainList { get { if ((Object)(object)section != (Object)null && (Object)(object)current == (Object)(object)section) { return section.activeInHierarchy; } return false; } } public static void Tick() { //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) Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name != "Menu") { section = null; return; } if ((Object)(object)section == (Object)null) { section = Util.FindAny("Managers/Menu/Main Menu/Canvas/Main Menu/TextSection"); if ((Object)(object)section == (Object)null) { return; } pcHome = (pcJoin = null); current = section; anims.Clear(); } if ((Object)(object)pcHome == (Object)null && !Build()) { return; } if (InProCon && !((Component)section.transform.parent).gameObject.activeInHierarchy) { Show(section); } int num; if ((Object)(object)current != (Object)null) { num = (current.activeInHierarchy ? 1 : 0); if (num != 0 && !wasVisible) { PlayEntrance(); } } else { num = 0; } wasVisible = (byte)num != 0; if (num != 0) { if (InProCon) { ProConInput(); } Animate(); } } private static bool Build() { //IL_01bd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)MenuFont.Font == (Object)null) { return false; } MenuFont.Apply(((Component)section.transform.parent).gameObject); Transform val = section.transform.Find("Online"); if ((Object)(object)val == (Object)null) { return false; } template = ((Component)val).gameObject; MakeButton(section.transform, "ProCon", delegate { Show(pcHome); }).transform.SetSiblingIndex(val.GetSiblingIndex() + 1); Navigate(section); pcHome = MakePage("ProCon Home"); MakeButton(pcHome.transform, "Host", OnHost); MakeButton(pcHome.transform, "Join", delegate { Show(pcJoin); }); MakeButton(pcHome.transform, "Back", delegate { Show(section); }); hintLabel = MakeLabel(pcHome.transform, Session.StatusLine(), 0.5f); Navigate(pcHome); pcJoin = MakePage("ProCon Join"); MakeLabel(pcJoin.transform, "Enter code", 0.6f); codeLabel = MakeLabel(pcJoin.transform, "", 1.25f); ((Graphic)codeLabel).color = Color.white; codeLabel.characterSpacing = 14f; MakeButton(pcJoin.transform, "Connect", OnConnect); MakeButton(pcJoin.transform, "Back", delegate { Show(pcHome); }); Navigate(pcJoin); MelonLogger.Msg("ProCon added to main menu."); return true; } private static GameObject MakePage(string name) { GameObject val = Object.Instantiate(section, section.transform.parent); ((Object)val).name = name; for (int num = val.transform.childCount - 1; num >= 0; num--) { Object.DestroyImmediate((Object)(object)((Component)val.transform.GetChild(num)).gameObject); } val.SetActive(false); return val; } private static GameObject Clone(Transform parent, string name, string text) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate(template, parent); ((Object)val).name = name; val.SetActive(true); foreach (Component component in val.GetComponents()) { if (!((Object)(object)component == (Object)null)) { switch (((MemberInfo)((Object)component).GetIl2CppType()).Name) { case "LocalizeStringEvent": case "DisabledIfPlatform": case "MainUserInteractOnly": Object.DestroyImmediate((Object)(object)component); break; } } } val.transform.localScale = Vector3.one; val.GetComponent().text = text; return val; } private static GameObject MakeButton(Transform parent, string text, Action onClick) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown GameObject obj = Clone(parent, text, text); Button component = obj.GetComponent