Decompiled source of LobbyExpansion v1.2.0
GTFO.LobbyExpansion.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; 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.Text.Json; using AIGraph; using AK; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using BepInEx.Unity.IL2CPP.Utils.Collections; using BoosterImplants; using CellMenu; using ChainedPuzzles; using Enemies; using GTFO.LobbyExpansion.Compatibility; using GTFO.LobbyExpansion.Patches.Manual; using GTFO.LobbyExpansion.Util; using GameData; using Gear; using HarmonyLib; using Il2CppInterop.Common; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Microsoft.CodeAnalysis; using Player; using PlayerCoverage; using SNetwork; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.Events; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("GTFO.LobbyExpansion")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0+ea67d177812701a88f8595fa66562a452cf4b87b")] [assembly: AssemblyProduct("GTFO.LobbyExpansion")] [assembly: AssemblyTitle("GTFO.LobbyExpansion")] [assembly: TargetPlatform("Windows7.0")] [assembly: SupportedOSPlatform("Windows7.0")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NativeIntegerAttribute : Attribute { public readonly bool[] TransformFlags; public NativeIntegerAttribute() { TransformFlags = new bool[1] { true }; } public NativeIntegerAttribute(bool[] P_0) { TransformFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace GTFO.LobbyExpansion { public static class CoolButton { private const float ALPHA_OVER = 1f; private const float ALPHA_OVER_DISABLED = 0.25f; private const float ALPHA_OUT = 0.66f; private const float ALPHA_OUT_DISABLED = 0.25f; private static readonly Color COLOR_OUT = new Color(1f, 1f, 1f, 0.66f); private static readonly Color COLOR_HOVER = new Color(1f, 1f, 1f, 1f); private static readonly Color COLOR_DISABLED = new Color(1f, 1f, 1f, 0.25f); private static GameObject _squareButtonPrefab = null; public static void SetCoolButtonEnabled(this CM_Item button, bool enabled) { //IL_003f: 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_0054: 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) if (!((Object)(object)button == (Object)null)) { button.m_spriteAlphaOut = (enabled ? 0.66f : 0.25f); button.m_spriteAlphaOver = (enabled ? 1f : 0.25f); button.m_spriteColorOut = (enabled ? COLOR_OUT : COLOR_DISABLED); button.m_spriteColorOver = (enabled ? COLOR_HOVER : COLOR_DISABLED); button.OnHoverOut(); ((Behaviour)button.m_collider).enabled = enabled; } } internal static void Setup(CM_PageLoadout pageLoadout) { if (!((Object)(object)_squareButtonPrefab != (Object)null)) { _squareButtonPrefab = CreateButtonPrefab(pageLoadout); } } public static CM_Item InstantiateSquareButton(Transform parent, Vector3 position, bool hideText = false, bool displayArrow = false, bool flipArrow = false) { //IL_001e: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown GameObject val = Object.Instantiate<GameObject>(_squareButtonPrefab, parent); val.gameObject.SetActive(true); val.transform.localPosition = position; CM_Item component = val.GetComponent<CM_Item>(); if (hideText) { ((Component)val.transform.Find("MainText")).gameObject.SetActive(false); } Transform val2 = val.transform.Find("Arrow"); ((Component)val2).gameObject.SetActive(displayArrow); if (flipArrow) { val2.localRotation = Quaternion.Euler(0f, 0f, -90f); } component.m_hoverSpriteArray = Il2CppReferenceArray<SpriteRenderer>.op_Implicit(((IEnumerable<SpriteRenderer>)val.gameObject.GetComponentsInChildren<SpriteRenderer>(true)).ToArray()); foreach (SpriteRenderer item in (Il2CppArrayBase<SpriteRenderer>)(object)component.m_hoverSpriteArray) { item.color = new Color(1f, 1f, 1f, 0.66f); } component.m_spriteAlphaOver = 1f; component.m_spriteAlphaOut = 0.66f; component.m_alphaSpriteOnHover = true; component.m_onBtnPress = new UnityEvent(); ((RectTransformComp)component).Setup(); return component; } private static GameObject CreateButtonPrefab(CM_PageLoadout pageLoadout) { //IL_009a: 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_00e3: 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_025b: Unknown result type (might be due to invalid IL or missing references) //IL_026f: 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_019d: 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_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: 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) //IL_022d: Unknown result type (might be due to invalid IL or missing references) CM_Item component = Object.Instantiate<GameObject>(pageLoadout.m_readyButtonPrefab).GetComponent<CM_Item>(); GameObject gameObject = ((Component)component).gameObject; Transform transform = gameObject.transform; Object.Destroy((Object)(object)component); component = gameObject.AddComponent<CM_Item>(); Object.Destroy((Object)(object)((Component)transform.Find("PressAndHold")).gameObject); Object.Destroy((Object)(object)((Component)transform.Find("ProgressFillBase")).gameObject); Object.Destroy((Object)(object)((Component)transform.Find("ProgressFill")).gameObject); Object.Destroy((Object)(object)((Component)transform.Find("Progress")).gameObject); transform.Find("MainText").localPosition = new Vector3(-20f, -18f, 0f); component.SetText("<color=white>P1</color>"); Transform obj = transform.Find("Arrow"); obj.localPosition = new Vector3(0f, -40f, 0f); obj.localScale = new Vector3(0.3f, 0.3f, 1f); Transform val = transform.Find("Box"); val.localPosition = new Vector3(0f, -40f, 0f); for (int i = 0; i < val.childCount; i++) { Transform child = val.GetChild(i); switch (((Object)child).name) { case "StretchLineT": child.localScale = new Vector3(0.22f, 4f, 1f); child.localPosition = new Vector3(-45f, 45f, 0f); break; case "StretchLineB": child.localScale = new Vector3(0.22f, 4f, 1f); child.localPosition = new Vector3(-45f, -45f, 0f); break; case "StretchLineR": child.localPosition = new Vector3(45f, 45f, 0f); break; case "StretchLineL": child.localScale = new Vector3(0.5f, 1f, 1f); child.localPosition = new Vector3(-45f, 45f, 0f); break; } } BoxCollider2D component2 = ((Component)component).GetComponent<BoxCollider2D>(); component2.size = new Vector2(80f, 80f); ((Collider2D)component2).offset = new Vector2(0f, -40f); ((Object)component).name = "LobbyExpander_SwitchLobbyButton"; Object.DontDestroyOnLoad((Object)(object)gameObject); ((Object)gameObject).hideFlags = (HideFlags)61; gameObject.SetActive(false); return gameObject; } } public static class HarmonyControlFlow { public const bool DontExecute = false; public const bool Execute = true; } internal static class L { private static readonly ManualLogSource Logger; static L() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown Logger = new ManualLogSource("GTFO.LobbyExpansion"); Logger.Sources.Add((ILogSource)(object)Logger); } internal static void Assert([DoesNotReturnIf(false)] bool condition, object data) { if (!condition) { string text = "ASSERTION FAILED: " + Format(data); Fatal(text); throw new ApplicationException(text); } } [Conditional("DEBUG")] internal static void DebugWarning(object data) { Warning("-------------------------------------------"); Warning("-------------- DEBUG WARNING --------------"); Warning(Format(data)); Warning("-------------------------------------------"); } [Conditional("DEBUG")] internal static void Debug(object data) { Logger.LogDebug((object)Format(data)); } internal static void Info(object data) { Logger.LogMessage((object)Format(data)); } [Conditional("DEBUG")] internal static void Verbose(object data) { Logger.LogDebug((object)Format(data)); } internal static void Error(object data) { Logger.LogError((object)Format(data)); } internal static void Fatal(object data) { Logger.LogFatal((object)Format(data)); } internal static void Warning(object data) { Logger.LogWarning((object)Format(data)); } [Conditional("DEBUG")] internal static void LogExecutingMethod(string? parameterInfo = "") { MethodBase method = new StackFrame(1, needFileInfo: false).GetMethod(); if (method == null) { Error("COULD NOT LOG EXECUTING METHOD. THIS SHOULD NOT HAPPEN."); return; } _ = method.DeclaringType?.FullName; _ = method.Name; if (!string.IsNullOrWhiteSpace(parameterInfo)) { _ = " (" + parameterInfo + ")"; } } private static string Format(object msg) { return msg.ToString() ?? ""; } } public class LobbyExpansionPlayerCount { public byte MaxPlayers { get; set; } = 8; } public class LobbyExpansionConfig { public Dictionary<int, SlotPermission>? SlotPermissions { get; set; } = new Dictionary<int, SlotPermission>(); public List<string>? CustomExtraBotNames { get; set; } = new List<string>(); } public class Pagination { public int PageIndex { get; set; } public event Action? OnPageChanged; public bool CanPageUp() { int num = (int)Math.Ceiling((double)(int)PluginConfig.MaxPlayers / 4.0) - 1; return PageIndex < num; } public bool PageUp() { if (CanPageUp()) { PageIndex++; this.OnPageChanged?.Invoke(); return true; } return false; } public bool CanPageDown() { return PageIndex > 0; } public bool PageDown() { if (CanPageDown()) { PageIndex--; this.OnPageChanged?.Invoke(); return true; } return false; } public static int GetLocalPlayerPageIndexFromPillar() { foreach (CM_PlayerLobbyBar item in (Il2CppArrayBase<CM_PlayerLobbyBar>)(object)CM_PageLoadout.Current.m_playerLobbyBars) { if (item.m_player.IsLocal) { return GetPageFromSlotIndex(item.PlayerSlotIndex); } } return 0; } public static int GetLocalPlayerPageFromSlotIndex() { return GetPageFromSlotIndex(SNet.LocalPlayer.PlayerSlot.index); } public static int GetPageFromSlotIndex(int slotIndex) { return (int)Math.Floor((float)slotIndex / 4f); } } public class PatchingException : Exception { public PatchingException(string? message) : base(message) { } public PatchingException(string? message, Exception? innerException) : base(message, innerException) { } } [BepInPlugin("GTFO.LobbyExpansion", "GTFO.LobbyExpansion", "1.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BasePlugin { private Harmony _harmony; public override void Load() { //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Expected O, but got Unknown try { PluginConfig.Load(); } catch (Exception ex) { L.Error("Failed to load plugin config?!"); L.Error(ex.GetType().Name + ": " + ex.Message); L.Warning("StackTrace:\n" + ex.StackTrace); } try { HashSet<Type> hashSet = new HashSet<Type>(); foreach (ManualPatch item in new List<ManualPatch> { new CM_PageExpeditionSuccessManualPatch(), new CM_PageLoadoutManualPatch(), new CM_PageMapManualPatch(), new CM_PlayerLobbyBarManualPatch(), new DiscordManagerManualPatch(), new GuiManagerManualPatch(), new PLOC_InElevatorManualPatch(), new PlayerAgentManualPatch(), new PlayerBotAIDataManualPatch(), new PlayerCoverageDataSet_NodeManualPatch(), new PlayerCoverageDataSet_PortalManualPatch(), new PlayerManagerManualPatch(), new PlayerSessionStatusManagerManualPatch(), new PlayerVoiceManagerManualPatch(), new SNet_PlayerSlotManagerManualPatch(), new SNet_SyncManagerManualPatch(), new CM_PageLoadoutDisplayClassManualPatch() }) { Type type = item.GetType(); if (hashSet.Contains(type)) { string obj = $"The same patch {type} is being applied twice. Fix this."; L.Fatal(obj); throw new PatchingException(obj); } item.Apply(); hashSet.Add(type); } } catch (Exception data) { L.Fatal("An error occurred while applying manual patches:"); L.Fatal(data); return; } try { _harmony = new Harmony("GTFO.LobbyExpansion"); _harmony.PatchAll(); } catch (Exception data2) { L.Fatal("An error occurred while applying patches:"); L.Fatal(data2); return; } foreach (ModCompatibilityPatch item2 in new List<ModCompatibilityPatch> { new PacksHelperPatch(), ChatterRebornPatch.Instance }) { string name = item2.GetType().Name; try { if (!item2.ShouldApply()) { return; } L.Info("Applying mod compatibility patch " + name + "."); item2.Apply(_harmony); } catch (Exception data3) { L.Fatal("An error occurred while applying mod compatibility patch " + name + ":"); L.Fatal(data3); return; } } L.Info("Loaded plugin GTFO.LobbyExpansion."); } } public static class PluginConfig { public const byte DEFAULT_MAX_PLAYERS = 8; private const string CONFIG_FILE_NAME = "LobbyExpansionConfig.json"; private const string USER_CONFIG_FILE_NAME = "LobbyExpansionConfig_UserData.json"; private static readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions { WriteIndented = true }; private static readonly string _configPath = Path.Combine(Paths.ConfigPath, "LobbyExpansionConfig.json"); private static readonly string _configPathUserData = Path.Combine(Paths.ConfigPath, "LobbyExpansionConfig_UserData.json"); internal static byte MaxPlayers = 8; private static LobbyExpansionPlayerCount _configPlayerCount = new LobbyExpansionPlayerCount(); private static LobbyExpansionConfig _configUserData = new LobbyExpansionConfig(); internal static void Load() { LoadCustomPlayerCount(); if (!File.Exists(_configPathUserData)) { SaveUserData(); } _configUserData = JsonSerializer.Deserialize<LobbyExpansionConfig>(File.ReadAllText(_configPathUserData), _serializerOptions) ?? new LobbyExpansionConfig(); LobbyExpansionConfig configUserData = _configUserData; if (configUserData.SlotPermissions == null) { Dictionary<int, SlotPermission> dictionary2 = (configUserData.SlotPermissions = new Dictionary<int, SlotPermission>()); } configUserData = _configUserData; if (configUserData.CustomExtraBotNames == null) { List<string> list2 = (configUserData.CustomExtraBotNames = new List<string>()); } } private static void LoadCustomPlayerCount() { if (File.Exists(_configPath)) { _configPlayerCount = JsonSerializer.Deserialize<LobbyExpansionPlayerCount>(File.ReadAllText(_configPath), _serializerOptions) ?? new LobbyExpansionPlayerCount(); if (_configPlayerCount.MaxPlayers < 4) { L.Error("ConfigFile: MaxPlayers must be greater or equal to '4'!"); MaxPlayers = 8; return; } L.Info($"Loaded custom player count from config file: {MaxPlayers} (default) -> {_configPlayerCount.MaxPlayers} (config)"); MaxPlayers = _configPlayerCount.MaxPlayers; } } private static void SaveUserData() { string contents = JsonSerializer.Serialize(_configUserData, _serializerOptions); File.WriteAllText(_configPathUserData, contents); } public static SlotPermission GetExtraSlotPermission(int slotIndex) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) return _configUserData.SlotPermissions.GetValueOrDefault(slotIndex, (SlotPermission)4); } public static void SetExtraLobbySlotPermissions(int slotIndexMinusOne, SlotPermission permission) { //IL_0030: 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) int num = slotIndexMinusOne + 1; L.Info($"SetExtraLobbySlotPermissions called: slotIndex:{num}, SlotPermission:{permission}"); _configUserData.SlotPermissions[num] = permission; SaveUserData(); } public static string GetExtraSlotNickname(int characterIndex) { int num = characterIndex - 4; if (_configUserData.CustomExtraBotNames.Count > 0 && num < _configUserData.CustomExtraBotNames.Count) { string text = _configUserData.CustomExtraBotNames[num]; if (!string.IsNullOrWhiteSpace(text)) { return text; } } return characterIndex switch { 4 => "Schaeffer", 5 => "North", 6 => "Henriksson", 7 => "Maddox", _ => $"Prisoner{characterIndex}", }; } } internal static class PluginInfo { internal const string Guid = "GTFO.LobbyExpansion"; internal const string Name = "GTFO.LobbyExpansion"; internal const string Version = "1.2.0"; } } namespace GTFO.LobbyExpansion.Util { public static class BepInExUtil { public static bool IsPluginLoaded(string pluginGuid) { return ((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.ContainsKey(pluginGuid); } public static object GetPluginInstance(string pluginGuid) { if (!((BaseChainloader<BasePlugin>)(object)IL2CPPChainloader.Instance).Plugins.TryGetValue(pluginGuid, out var value)) { throw new InvalidOperationException("Could not retrieve plugin info for plugin with GUID " + pluginGuid + "."); } return value.Instance ?? throw new InvalidOperationException("Plugin with GUID " + pluginGuid + " had a null instance."); } } public static class CoroutineHelpers { public static IEnumerator NextFrame(Action action) { yield return null; action?.Invoke(); } } public abstract class ManualPatch { protected record Patch { public string Method { get; init; } = ""; public string Description { get; init; } = ""; public string Pattern { get; init; } = ""; public int Offset { get; init; } public byte[] Bytes { get; init; } = Array.Empty<byte>(); public long? ScanSize { get; init; } public Type[]? ParameterTypes { get; init; } = Array.Empty<Type>(); } private static readonly HashSet<IntPtr> PatchedAddresses = new HashSet<IntPtr>(); protected const byte NOP = 144; protected List<Patch> Patches { get; } = new List<Patch>(); protected abstract Type TargetType { get; } public void Apply() { SetupPatches(); foreach (Patch patch in Patches) { Type[] parameterTypes = patch.ParameterTypes ?? Array.Empty<Type>(); string method = patch.Method; bool flag = ((method == ".ctor" || method == "ctor") ? true : false); nint num = Memory.FindSignatureInIl2CppMethod(flag ? Memory.GetIl2CppConstructorAddress(TargetType, parameterTypes) : Memory.GetIl2CppMethodAddress(TargetType, patch.Method, parameterTypes), patch.Pattern, patch.ScanSize); if (num == 0) { throw new PatchingException("Could not find pattern for patch \"" + patch.Description + "\"."); } nint num2 = num + patch.Offset; if (PatchedAddresses.Contains(num2)) { string text = "Patching the same address " + ((IntPtr)num2).ToString("X") + "! Something is wrong!"; L.Fatal(text); throw new PatchingException(text); } Memory.PatchMemory(num2, patch.Bytes); PatchedAddresses.Add(num2); } } protected abstract void SetupPatches(); protected static byte[] GenerateNop(int count) { if (count <= 0) { throw new ArgumentException("Count must be greater than 0.", "count"); } return Enumerable.Repeat((byte)144, count).ToArray(); } } public static class Memory { private record Signature(byte[] Bytes, char[] Mask); private const long DefaultBlockScanSize = 3000L; public static nint GetIl2CppConstructorAddress(Type type, params Type[] parameterTypes) { ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, parameterTypes); if (constructor == null) { IEnumerable<string> value = parameterTypes.Select((Type x) => x.FullName?.ToString() ?? "null"); throw new MissingMethodException($"Could not find constructor for {type.FullName} with {parameterTypes.Length} parameters ({value})."); } return GetIl2CppMethodAddress(type, constructor); } public static nint GetIl2CppConstructorAddress<T>(params Type[] parameterTypes) where T : Il2CppObjectBase { return GetIl2CppConstructorAddress(typeof(T), parameterTypes); } public static nint GetIl2CppMethodAddress(Type type, string methodName) { return GetIl2CppMethodAddress(type, methodName, Array.Empty<Type>()); } public static nint GetIl2CppMethodAddress(Type type, string methodName, Type[] parameterTypes) { MethodInfo method = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); if (method == null) { string value = ""; if (parameterTypes.Length != 0) { value = $" with {parameterTypes.Length} parameters (${string.Join(", ", parameterTypes.Select((Type x) => x.FullName?.ToString() ?? x.Name))})"; } throw new MissingMethodException($"Could not find method {methodName} in type {type.FullName}{value}."); } return GetIl2CppMethodAddress(type, method); } public static nint GetIl2CppMethodAddress<T>(string methodName) where T : Il2CppObjectBase { return GetIl2CppMethodAddress<T>(methodName, Array.Empty<Type>()); } public static nint GetIl2CppMethodAddress<T>(string methodName, Type[] parameterTypes) where T : Il2CppObjectBase { return GetIl2CppMethodAddress(typeof(T), methodName, parameterTypes); } public unsafe static nint GetIl2CppMethodAddress(Type type, MethodBase methodBase) { FieldInfo il2CppMethodInfoPointerFieldForGeneratedMethod = Il2CppInteropUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(methodBase); if (il2CppMethodInfoPointerFieldForGeneratedMethod == null) { throw new MissingFieldException($"Could not find IL2CPP method info pointer field for method {methodBase} of {type.FullName ?? type.Name}."); } return *(nint*)(void*)(IntPtr)(il2CppMethodInfoPointerFieldForGeneratedMethod.GetValue(null) ?? throw new NullReferenceException($"Method info pointer field for method {methodBase} of {type.FullName ?? type.Name} was null.")); } public static nint GetIl2CppMethodAddress<T>(MethodBase methodBase) where T : Il2CppObjectBase { return GetIl2CppMethodAddress(typeof(T), methodBase); } public static nint FindSignatureInIl2CppMethod(nint methodPointer, string signature, long? blockSize) { Signature signature2 = ConvertAobToSignature(signature); if (signature2 == null) { throw new ArgumentException("signature was an invalid signature."); } return FindSignatureInBlock(methodPointer, blockSize.GetValueOrDefault(3000L), signature2.Bytes, signature2.Mask); } public static nint FindSignatureInIl2CppMethod<T>(string methodName, string signature, long blockSize = 3000L) where T : Il2CppObjectBase { return FindSignatureInIl2CppMethod(GetIl2CppMethodAddress<T>(methodName), signature, blockSize); } public static void PatchMemory(IntPtr address, byte[] bytes) { if (address == IntPtr.Zero) { throw new ArgumentException("address cannot be zero."); } if (!Win32.VirtualProtect(address, new IntPtr(bytes.Length), Win32.MemoryProtection.ExecuteReadWrite, out var lpflOldProtect)) { throw new Exception($"VirtualProtect failed for address {address}."); } bool flag = false; try { for (int i = 0; i < bytes.Length; i++) { Marshal.WriteByte(address, i, bytes[i]); } } catch (Exception value) { Console.WriteLine(value); throw; } finally { try { flag = Win32.VirtualProtect(address, new IntPtr(bytes.Length), lpflOldProtect, out var _); } catch { L.Error($"VirtualProtect failed to restore protection for address {address}."); } } if (!flag) { throw new Exception($"VirtualProtect failed to restore protection for address {address}."); } } private unsafe static nint FindSignatureInBlock(nint block, long blockSize, byte[] pattern, char[] mask) { for (long num = 0L; num < blockSize; num++) { bool flag = true; for (uint num2 = 0u; num2 < mask.Length; num2++) { if (*(byte*)(num + block + num2) != pattern[num2] && mask[num2] != '?') { flag = false; break; } } if (flag) { return (nint)(num + block); } } return 0; } private static Signature? ConvertAobToSignature(string signature) { if (string.IsNullOrWhiteSpace(signature)) { return null; } string[] array = signature.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); if (array.Length == 0) { return null; } byte[] array2 = new byte[array.Length]; char[] array3 = new char[array.Length]; for (int i = 0; i < array.Length; i++) { string text = array[i]; if ((text == "?" || text == "??") ? true : false) { array2[i] = 0; array3[i] = '?'; } else { array2[i] = byte.Parse(text, NumberStyles.HexNumber); array3[i] = 'x'; } } return new Signature(array2, array3); } } public static class ReflectionUtil { public static void SetStaticField(Type type, string fieldName, object value) { FieldInfo? field = type.GetField(fieldName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { throw new ArgumentException($"Could not find static field '{fieldName}' in type '{type.FullName}'.", "fieldName"); } field.SetValue(null, value); } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] public static Type GetRequiredTypeByName(string name, Assembly assembly) { Type[] types = assembly.GetTypes(); foreach (Type type in types) { if (type.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) { return type; } } throw new ArgumentException($"Could not find type '{name}' in assembly '{assembly.FullName ?? "unnamed"}'."); } } public static class Win32 { [Flags] public enum MemoryProtection : uint { NoAccess = 1u, ReadOnly = 2u, ReadWrite = 4u, WriteCopy = 8u, Execute = 0x10u, ExecuteRead = 0x20u, ExecuteReadWrite = 0x40u, ExecuteWriteCopy = 0x80u, GuardModifierflag = 0x100u, NoCacheModifierflag = 0x200u, WriteCombineModifierflag = 0x400u } [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, MemoryProtection flNewProtect, out MemoryProtection lpflOldProtect); } } namespace GTFO.LobbyExpansion.Patches.Manual { public class CM_PageExpeditionSuccessManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(CM_PageExpeditionSuccess); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlySingleElementList<Patch>(new Patch { Method = "Setup", Description = "Adjust hardcoded m_playerReports size in Setup.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 4C 8D BE F0 01 00 00", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } })); } } public class CM_PageLoadoutDisplayClassManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(__c__DisplayClass38_1); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlySingleElementList<Patch>(new Patch { Method = "_ShowPermissionWindow_b__1", Description = "NOP out Il2Cpp check and assignment of CellSettingsManager.SettingsData.Player.LobbySlotPermissions[num] = this.permission;", Pattern = "48 85 C9 74 5C 3B 71 18 73 7D 48 63 C6 89 54 81 20", Offset = 0, Bytes = ManualPatch.GenerateNop(17) })); } } public class CM_PageLoadoutManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(CM_PageLoadout); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlySingleElementList<Patch>(new Patch { Method = "Setup", Description = $"Adjust CM_PageLoadout Setup m_playerLobbyBars size from 4 -> {PluginConfig.MaxPlayers}.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 48 8B D0 48 89 87 08 02 00 00", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } })); } } public class CM_PageMapManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(CM_PageMap); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlyArray<Patch>(new Patch[13] { new Patch { Method = "TryGetInventoryWithSlotIndex", Description = "Remove CM_PageMap::TryGetInventoryWithSlotIndex slotIndex > 3", Pattern = "83 FF 03 77 60", Offset = 2, Bytes = new byte[1] { (byte)(PluginConfig.MaxPlayers - 1) } }, new Patch { Method = "Setup", Description = "Adjust CM_PageMap::Setup() m_inventory = new PUI_Inventory[4] to new max players.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 4C 8D B7 38 02 00 00", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "CreatePlayerIcons", Description = "Adjust CM_PageMap::CreatePlayerIcons() m_syncedPlayers = new CM_MapPlayerGUIItem[4] to new max players.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 49 8D AF 50 02 00 00", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "CreatePlayerIcons", Description = "Adjust CM_PageMap::CreatePlayerIcons() m_syncedCursors = new CM_Cursor[4] to new max players.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 4D 8D B7 58 02 00 00", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "CreatePlayerIcons", Description = "Adjust CM_PageMap::CreatePlayerIcons() m_drawPixelBufferIndex = new int[4] to new max players.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 49 8D 8F 80 02 00 00", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "CreatePlayerIcons", Description = "Adjust CM_PageMap::CreatePlayerIcons() m_drawPixelBuffer = new CM_MapDrawPixel[4][] to new max players.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 48 8B D0 49 89 87 78 02 00 00", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "CreatePlayerIcons", Description = "Adjust CM_PageMap::CreatePlayerIcons() m_lastDrawingPos = new Vector2[4] to new max players.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 49 8D 8F 68 02 00 00", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "CreatePlayerIcons", Description = "Adjust CM_PageMap::CreatePlayerIcons() for (int i = 0; i < 4; i++) to new max players.", Pattern = "83 FE 04 0F 8C A9 FC FF FF", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "UpdatePlayerData", Description = "Adjust CM_PageMap::UpdatePlayerData() for (int i = 0; i < 4; i++) to new max players.", Pattern = "83 FB 04 0F 8C 21 FF FF FF", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "UpdateSyncedCursorVisibility", Description = "Adjust CM_PageMap::UpdateSyncedCursorVisibility() for (int i = 0; i < 4; i++) to new max players.", Pattern = "83 FB 04 0F 8C 61 FF FF FF", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "Update", Description = "Adjust CM_PageMap::UpdateSyncedCursorVisibility() (Inlined into Update()!) for (int i = 0; i < 4; i++) to new max players.", Pattern = "83 FB 04 0F 8C 55 FF FF FF", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "SetPageActive", Description = "Adjust CM_PageMap::SetPageActive() m_playerIsDrawing = new bool[4] to new max players.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 48 8D 8B 60 02 00 00", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "OnEnable", Description = "Adjust CM_PageMap::OnEnable() for (int i = 0; i < 4; i++) to new max players.", Pattern = "83 FE 04 7C 94", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } } })); } } public class CM_PlayerLobbyBarManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(CM_PlayerLobbyBar); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlySingleElementList<Patch>(new Patch { Method = "UpdatePlayer", Description = "Adjust hardcoded limit of 4 in CM_PlayerLobbyBar::UpdatePlayer to new max players.", Pattern = "83 F8 04 0F 8D F0 00 00 00", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } })); } } public class DiscordManagerManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(DiscordManager); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlySingleElementList<Patch>(new Patch { Method = "GetMaxLobbySize", Description = "Adjust DiscordManager::GetMaxLobbySize hardcoded iteration to new max players.", Pattern = "BF 04 00 00 00 33 DB", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } })); } } public class GuiManagerManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(GuiManager); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlySingleElementList<Patch>(new Patch { Method = "Setup", Description = "Adjust GuiManager::Setup() m_playerPings = new SyncedNavMarkerWrapper[4] to new max players.", Pattern = "BA 04 00 00 00 4C 8B E8", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers }, ScanSize = 7500L })); } } public class PlayerAgentManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(PlayerAgent); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlyArray<Patch>(new Patch[2] { new Patch { Method = "Setup", Description = "Remove characterID limit in PlayerAgent::Setup", Pattern = "0F 87 12 10 00 00", Offset = 0, Bytes = ManualPatch.GenerateNop(6) }, new Patch { Method = "Setup", Description = "Remove characterID >= m_modelsForSync length in PlayerAgent::Setup since m_modelsForSync isn't used anyway", Pattern = "44 3B 70 18 0F 8D F8 0F 00 00", Offset = 4, Bytes = ManualPatch.GenerateNop(6) } })); } } public class PlayerCoverageDataSet_NodeManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(PlayerCoverageDataSet_Node); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlyArray<Patch>(new Patch[4] { new Patch { Method = ".ctor", Description = "Patch PlayerCoverageDataSet_Node constructor and PlayerCoverageDataSet_Portal$$ constructor (#1)", Pattern = "FF C6 83 FE 04 7C 8D 48 8B 5C 24 30", Offset = 4, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = ".ctor", Description = $"Patch PlayerCoverageDataSet_Node constructor m_coverageDatas array size from 4 -> {PluginConfig.MaxPlayers}.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 4C 8D 73 10 48 8B D0 49 8B CE 49 89 06 E8 ?? ?? ?? ?? 33 D2", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "GetNodeDistanceToClosestPlayer", Description = "Adjust GetNodeDistanceToClosestPlayer hardcoded iteration of 4.", Pattern = "83 F9 04 7C CC", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "GetNodeDistanceToClosestPlayer_Unblocked", Description = "Adjust GetNodeDistanceToClosestPlayer_Unblocked hardcoded iteration of 4.", Pattern = "83 FB 04 0F 8C 5B FF FF FF", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } } })); } } public class PlayerCoverageDataSet_PortalManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(PlayerCoverageDataSet_Portal); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlyArray<Patch>(new Patch[2] { new Patch { Method = ".ctor", ParameterTypes = new Type[1] { typeof(AIG_CoursePortal) }, Description = "Patch PlayerCoverageDataSet_Portal constructor (#1) for loop", Pattern = "FF C6 83 FE 04 7C 8D 48 8B 5C 24 30", Offset = 4, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = ".ctor", ParameterTypes = new Type[1] { typeof(AIG_CoursePortal) }, Description = $"Patch PlayerCoverageDataSet_Portal constructor m_coverageDatas array size from 4 -> {PluginConfig.MaxPlayers}.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 4C 8D 73 10 48 8B D0 49 8B CE 49 89 06 E8 ?? ?? ?? ?? 33 F6", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } } })); } } public class PlayerManagerManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(PlayerManager); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlyArray<Patch>(new Patch[4] { new Patch { Method = "SpawnBot", Description = "Remove SpawnBot hardcoded limit of 4.", Pattern = "83 78 18 04 0F 84 C0 03 00 00", Offset = 4, Bytes = ManualPatch.GenerateNop(6) }, new Patch { Method = ".ctor", Description = "Set constructor m_botSlot size to new max player limit.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 48 8D 4E 70", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = ".ctor", Description = "Patch inlined version of the creation of PositionReservations in PlayerManager constructor.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 48 8D 4F 20 48 8B D0 48 89 01 E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? BA 04 00 00 00 E8 ?? ?? ?? ?? 48 8D 4F 28 48 8B D0 48 89 01 E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 8B C8 48 8B D8 E8 ?? ?? ?? ?? 48 8D 4F 30 48 8B D3 48 89 19 E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 8B C8 48 8B D8 E8 ?? ?? ?? ?? 48 8D 4F 38 48 8B D3 48 89 19 E8 ?? ?? ?? ?? 33 D2 48 8B CF E8", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = ".ctor", Description = "Patch inlined version of the creation of ObjectReservations in PlayerManager constructor.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 48 8D 4F 28 48 8B D0 48 89 01 E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 8B C8 48 8B D8 E8 ?? ?? ?? ?? 48 8D 4F 30 48 8B D3 48 89 19 E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 8B C8 48 8B D8 E8 ?? ?? ?? ?? 48 8D 4F 38 48 8B D3 48 89 19 E8 ?? ?? ?? ?? 33 D2 48 8B CF E8", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } } })); } } public class PlayerBotAIDataManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(PlayerBotAIData); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlyArray<Patch>(new Patch[2] { new Patch { Method = ".ctor", Description = "Set PlayerBotAIData constructor PositionReservations size to new max player limit.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 48 8D 4F 20 48 8B D0 48 89 01 E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? BA 04 00 00 00 E8 ?? ?? ?? ?? 48 8D 4F 28 48 8B D0 48 89 01 E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 8B C8 48 8B D8 E8 ?? ?? ?? ?? 48 8D 4F 30 48 8B D3 48 89 19 E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 8B C8 48 8B D8 E8 ?? ?? ?? ?? 48 8D 4F 38 48 8B D3 48 89 19 E8 ?? ?? ?? ?? 33 D2 48 8B CF 48 8B 5C 24 30", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = ".ctor", Description = "Set PlayerBotAIData constructor ObjectReservations size to new max player limit.", Pattern = "BA 04 00 00 00 E8 ?? ?? ?? ?? 48 8D 4F 28 48 8B D0 48 89 01 E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 8B C8 48 8B D8 E8 ?? ?? ?? ?? 48 8D 4F 30 48 8B D3 48 89 19 E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 8B C8 48 8B D8 E8 ?? ?? ?? ?? 48 8D 4F 38 48 8B D3 48 89 19 E8 ?? ?? ?? ?? 33 D2 48 8B CF 48 8B 5C 24 30", Offset = 1, Bytes = new byte[1] { PluginConfig.MaxPlayers } } })); } } public class PlayerSessionStatusManagerManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(PlayerSessionStatusManager); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlySingleElementList<Patch>(new Patch { Method = "OnPlayerStateCapture", Description = "Adjust PlayerSessionStatusManager::OnPlayerStateCapture() bool flag2 = characterIndex > -1 && characterIndex < 4; to new max players.", Pattern = "83 F8 04 0F 9C C3", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } })); } } public class PlayerVoiceManagerManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(PlayerVoiceManager); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlySingleElementList<Patch>(new Patch { Method = "RegisterPlayerVoice", Description = "Patch PlayerVoiceManager < 3", Pattern = "83 FE 03 76 67", Offset = 2, Bytes = new byte[1] { (byte)(PluginConfig.MaxPlayers - 1) } })); } } public class PLOC_InElevatorManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(PLOC_InElevator); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlySingleElementList<Patch>(new Patch { Method = "CommonEnter", Description = "PLOC_InElevator::CommonEnter PLOCStateReferenceID > 3", Pattern = "83 B8 A0 00 00 00 03", Offset = 6, Bytes = new byte[1] { (byte)(PluginConfig.MaxPlayers - 1) } })); } } public class SNet_PlayerSlotManagerManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(SNet_PlayerSlotManager); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlyArray<Patch>(new Patch[7] { new Patch { Method = "Internal_ManageSlot", Description = "Adjust Internal_ManageSlot hardcoded iteration of 4.", Pattern = "83 FF 04 0F 8C D1 FE FF FF", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "OnResetSession", Description = "Adjust OnResetSession hardcoded iteration of 4.", Pattern = "83 FB 04 7C 9E", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "OnValidateMasterData", Description = "Adjust OnValidateMasterData hardcoded iteration of 4.", Pattern = "83 FF 04 0F 8C 68 FE FF FF", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "HasFreeBotSlot", Description = "Adjust HasFreeBotSlot hardcoded iteration of 4.", Pattern = "83 FB 04 7C 87", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "HasFreeHumanSlot", Description = "Adjust HasFreeHumanSlot hardcoded iteration of 4.", Pattern = "83 FB 04 0F 8C 38 FF FF FF", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "SetAllPlayerSlotPermissions", Description = "Adjust SetAllPlayerSlotPermissions hardcoded iteration of 4.", Pattern = "83 FB 04 7C C7", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } }, new Patch { Method = "AreSlotPermissionsSet", Description = "Adjust AreSlotPermissionsSet hardcoded iteration of 4.", Pattern = "83 F8 04 7C EA", Offset = 2, Bytes = new byte[1] { PluginConfig.MaxPlayers } } })); } } public class SNet_SyncManagerManualPatch : ManualPatch { protected override Type TargetType { get; } = typeof(SNet_SyncManager); protected override void SetupPatches() { base.Patches.AddRange(new <>z__ReadOnlySingleElementList<Patch>(new Patch { Method = "ValidateIndex", Description = "Remove SNet_SyncManager::ValidateIndex character index > 3 check, since we're using higher characterIDs.", Pattern = "0F 87 C8 06 00 00", Offset = 0, Bytes = ManualPatch.GenerateNop(6) })); } } } namespace GTFO.LobbyExpansion.Patches.Harmony { [HarmonyPatch(typeof(BoosterImplantManager))] public static class BoosterImplantManagerPatch { [HarmonyPatch("Awake")] [HarmonyPostfix] public static void Awake__Postfix(BoosterImplantManager __instance) { if (((Il2CppArrayBase<PlayerBoosterImplantState>)(object)__instance.m_boosterPlayers).Length < PluginConfig.MaxPlayers) { __instance.m_boosterPlayers = new Il2CppReferenceArray<PlayerBoosterImplantState>((long)PluginConfig.MaxPlayers); } } } [HarmonyPatch(typeof(CM_PageExpeditionSuccess))] public static class CM_PageExpeditionSuccessPatch { private static bool _needPositionUpdate; private static DateTime _lastVisibilityUpdate = DateTime.Now; private static readonly Pagination _pagination = new Pagination(); private static CM_Item _buttonPageUp = null; private static CM_Item _buttonPageDown = null; [HarmonyPatch("OnEnable")] [HarmonyPostfix] public static void OnEnable__Postfix(CM_PageExpeditionSuccess __instance) { _pagination.PageIndex = 0; UpdateCustomButtons(); _needPositionUpdate = true; UpdateVisiblePlayerReports(__instance); } [HarmonyPatch("Update")] [HarmonyPostfix] public static void Update__Postfix(CM_PageExpeditionSuccess __instance) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (_needPositionUpdate) { for (int i = 4; i < ((Il2CppArrayBase<CM_PageSuccess_PrisonerEvaluation>)(object)__instance.m_playerReports).Length; i++) { Transform transform = ((Component)((Il2CppArrayBase<CM_PageSuccess_PrisonerEvaluation>)(object)__instance.m_playerReports)[i % 4]).transform; ((Component)((Il2CppArrayBase<CM_PageSuccess_PrisonerEvaluation>)(object)__instance.m_playerReports)[i]).transform.position = transform.position; ((Component)((Il2CppArrayBase<CM_PageSuccess_PrisonerEvaluation>)(object)__instance.m_playerReports)[i]).transform.parent = transform.parent; } _needPositionUpdate = false; } if (DateTime.Now > _lastVisibilityUpdate) { _lastVisibilityUpdate = DateTime.Now + TimeSpan.FromMilliseconds(50.0); UpdateVisiblePlayerReports(__instance); } if (Input.GetKeyDown((KeyCode)281)) { _pagination.PageDown(); } if (Input.GetKeyDown((KeyCode)280)) { _pagination.PageUp(); } } private static void UpdateVisiblePlayerReports(CM_PageExpeditionSuccess page) { if (page.m_playerReports == null) { return; } Il2CppReferenceArray<SNet_Slot> playerSlots = SNet.Slots.PlayerSlots; int num = _pagination.PageIndex * 4; int num2 = Math.Min(num + 4, PluginConfig.MaxPlayers); for (int i = 0; i < ((Il2CppArrayBase<CM_PageSuccess_PrisonerEvaluation>)(object)page.m_playerReports).Count; i++) { if (!((Object)(object)((Il2CppArrayBase<CM_PageSuccess_PrisonerEvaluation>)(object)page.m_playerReports)[i] == (Object)null)) { bool active = true; if (i < num) { active = false; } else if (i >= num2) { active = false; } else if (i >= ((Il2CppArrayBase<SNet_Slot>)(object)playerSlots).Count || (Object)(object)((Il2CppArrayBase<SNet_Slot>)(object)playerSlots)[i].player == (Object)null) { active = false; } ((Component)((Il2CppArrayBase<CM_PageSuccess_PrisonerEvaluation>)(object)page.m_playerReports)[i]).gameObject.SetActive(active); } } } private static void OnPageChanged() { UpdateVisiblePlayerReports(MainMenuGuiLayer.Current.PageExpeditionSuccess); UpdateCustomButtons(); } private static void UpdateCustomButtons() { bool enabled = _pagination.CanPageDown(); bool enabled2 = _pagination.CanPageUp(); _buttonPageDown.SetCoolButtonEnabled(enabled); _buttonPageUp.SetCoolButtonEnabled(enabled2); } [HarmonyPatch("Setup")] [HarmonyPostfix] public static void Setup__Postfix(CM_PageExpeditionSuccess __instance, MainMenuGuiLayer guiLayer) { CM_PageExpeditionSuccess __instance2 = __instance; _pagination.OnPageChanged += OnPageChanged; CoroutineManager.StartCoroutine(CollectionExtensions.WrapToIl2Cpp(CoroutineHelpers.NextFrame(delegate { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) _buttonPageUp = CoolButton.InstantiateSquareButton(((Component)__instance2.m_btnLeaveExpedition).transform, new Vector3(320f, 42f, 0f), hideText: true, displayArrow: true); _buttonPageDown = CoolButton.InstantiateSquareButton(((Component)__instance2.m_btnLeaveExpedition).transform, new Vector3(-320f, 42f, 0f), hideText: true, displayArrow: true, flipArrow: true); UpdateCustomButtons(); _buttonPageUp.OnBtnPressCallback = Action<int>.op_Implicit((Action<int>)delegate { _pagination.PageUp(); }); _buttonPageDown.OnBtnPressCallback = Action<int>.op_Implicit((Action<int>)delegate { _pagination.PageDown(); }); })), (Action)null); } } [HarmonyPatch(typeof(__c__DisplayClass38_1))] public class CM_PageLoadoutDisplayClassPatch { [HarmonyPatch("_ShowPermissionWindow_b__1")] public static void Prefix(__c__DisplayClass38_1 __instance) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) int num = 0; for (int i = 0; i < __instance.field_Public___c__DisplayClass38_0_0.playerIndex; i++) { SNet_Player player = ((Il2CppArrayBase<SNet_Slot>)(object)SNet.Slots.PlayerSlots)[i].player; if ((Object)(object)player == (Object)null || !player.IsLocal) { num++; } } if (num < 3) { ((Il2CppArrayBase<SlotPermission>)(object)CellSettingsManager.SettingsData.Player.LobbySlotPermissions)[num] = __instance.permission; } else { PluginConfig.SetExtraLobbySlotPermissions(num, __instance.permission); } } } [HarmonyPatch(typeof(CM_PageLoadout))] public static class CM_PageLoadoutPatch { private static CM_Item _centerButton = null; private static CM_Item _buttonPageDown = null; private static CM_Item _buttonPageUp = null; private const string DECOR_TEXT = "//: Lobby Page Switcher"; private static readonly Pagination _pagination = new Pagination(); [HarmonyPatch("Setup")] [HarmonyPrefix] public static bool Setup__Prefix(CM_PageLoadout __instance, MainMenuGuiLayer guiLayer) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) Il2CppReferenceArray<Transform> playerInfoHolders = __instance.m_playerInfoHolders; __instance.m_playerInfoHolders = new Il2CppReferenceArray<Transform>((long)PluginConfig.MaxPlayers); for (int i = 0; i < 4; i++) { ((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[i] = ((Il2CppArrayBase<Transform>)(object)playerInfoHolders)[i]; } GameObject val = GameObject.Find("GUI/CellUI_Camera(Clone)/MainMenuLayer/CM_PageLoadout_CellUI(Clone)/PlayerMovement/PlayerPillars"); L.Assert((Object)(object)val != (Object)null, "playerPillarsGameObj was null!"); for (int j = 4; j < PluginConfig.MaxPlayers; j++) { GameObject val2 = new GameObject($"Player{j + 1}Root"); Transform val3 = ((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[j % 4]; val2.transform.position = val3.position; val2.transform.localPosition = val3.localPosition; val2.transform.localScale = val3.localScale; val2.transform.SetParent(val.transform); val2.layer = LayerMask.NameToLayer("UI"); val2.SetActive(true); ((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[j] = val2.transform; } return true; } [HarmonyPatch("ArrangePlayerPillarSpacing")] [HarmonyPostfix] public static void ArrangePlayerPillarSpacing__Postfix(CM_PageLoadout __instance) { //IL_0019: 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_0036: 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) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_017a: 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_01b1: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (Vector3[])(object)new Vector3[4] { ((Component)((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[0]).transform.position, ((Component)((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[1]).transform.position, ((Component)((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[2]).transform.position, ((Component)((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[3]).transform.position }; for (int i = 4; i < PluginConfig.MaxPlayers; i++) { _ = $"Player{i + 1}Root"; Transform val = ((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[i % 4]; ((Component)((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[i]).transform.position = val.position; ((Component)((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[i]).transform.localPosition = val.localPosition; ((Component)((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[i]).transform.localScale = val.localScale; } int num = _pagination.PageIndex * 4; int num2 = Math.Min(num + 4, PluginConfig.MaxPlayers); for (int j = 0; j < ((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders).Count; j++) { if (j < num) { ((Component)((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[j]).gameObject.transform.position = new Vector3(5000f, 5000f, 5000f); } else if (j >= num2) { ((Component)((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[j]).gameObject.transform.position = new Vector3(5000f, 5000f, 5000f); } else { ((Component)((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[j]).transform.position = array[j % array.Length]; } } } public static void UpdatePlayerPillars() { CM_PageLoadout.Current.ArrangePlayerPillarSpacing(); } [HarmonyPatch("Update")] [HarmonyPostfix] public static void Update__Postfix(CM_PageLoadout __instance) { if (Input.GetKeyDown((KeyCode)281) && _pagination.PageDown()) { UpdateCustomButtons(); } if (Input.GetKeyDown((KeyCode)280) && _pagination.PageUp()) { UpdateCustomButtons(); } } [HarmonyPatch("ApplyPlayerSlotPermissionsFromSettings")] [HarmonyPostfix] public static void ApplyPlayerSlotPermissionsFromSettings__Postfix(CM_PageLoadout __instance) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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) bool flag = false; for (int i = 4; i < PluginConfig.MaxPlayers; i++) { SlotPermission extraSlotPermission = PluginConfig.GetExtraSlotPermission(i); if ((Object)(object)((Il2CppArrayBase<SNet_Slot>)(object)SNet.Slots.PlayerSlots)[i].player == (Object)null || !((Il2CppArrayBase<SNet_Slot>)(object)SNet.Slots.PlayerSlots)[i].player.IsLocal) { flag = SNet.Slots.SetSlotPermission(i, extraSlotPermission) || flag; } else if (((Il2CppArrayBase<SNet_Slot>)(object)SNet.Slots.PlayerSlots)[i].player.IsLocal) { flag = SNet.Slots.SetSlotPermission(i, (SlotPermission)4) || flag; } } if (!flag) { SNet.Core.OnSlotsStatusChanged(); } if (SNet_Events.OnLobbyPermissionsSet != null) { SNet_Events.OnLobbyPermissionsSet.Invoke(); } } [HarmonyPatch("OnDisable")] [HarmonyPostfix] public static void OnDisable__Postfix() { } private static void UpdateCustomButtons() { bool enabled = _pagination.CanPageDown(); bool enabled2 = _pagination.CanPageUp(); _buttonPageDown.SetCoolButtonEnabled(enabled); _buttonPageUp.SetCoolButtonEnabled(enabled2); _centerButton.SetText($"<color=white>P{_pagination.PageIndex + 1}</color>"); } private static void OnPageChanged() { UpdatePlayerPillars(); } [HarmonyPatch("Setup")] [HarmonyPostfix] public static void Setup__Postfix(CM_PageLoadout __instance, MainMenuGuiLayer guiLayer) { CM_PageLoadout __instance2 = __instance; if ((Object)(object)CM_PageLoadout.Current == (Object)null) { return; } _pagination.OnPageChanged += OnPageChanged; CoolButton.Setup(__instance2); CoroutineManager.StartCoroutine(CollectionExtensions.WrapToIl2Cpp(CoroutineHelpers.NextFrame(delegate { //IL_0005: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: 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) Transform transform = new GameObject("LobbySwitcherHolder").transform; transform.SetParent(__instance2.m_readyButtonAlign.parent); transform.localPosition = __instance2.m_readyButtonAlign.localPosition + new Vector3(0f, 1150f, 0f); transform.localScale = Vector3.one * 0.9f; Transform obj = Object.Instantiate<Transform>(__instance2.m_readyButtonAlign.Find("DecorText"), transform); ((Component)obj).transform.localPosition = new Vector3(100f, 0f, 0f); ((Component)obj).transform.localScale = Vector3.one; ((Component)obj).gameObject.SetActive(true); ((TMP_Text)((Component)obj).GetComponent<TextMeshPro>()).SetText("//: Lobby Page Switcher", true); _centerButton = CoolButton.InstantiateSquareButton(transform, Vector3.zero); _buttonPageDown = CoolButton.InstantiateSquareButton(transform, new Vector3(-110f, 0f, 0f), hideText: true, displayArrow: true, flipArrow: true); _buttonPageUp = CoolButton.InstantiateSquareButton(transform, new Vector3(110f, 0f, 0f), hideText: true, displayArrow: true); UpdateCustomButtons(); _centerButton.OnBtnPressCallback = Action<int>.op_Implicit((Action<int>)delegate { int localPlayerPageIndexFromPillar = Pagination.GetLocalPlayerPageIndexFromPillar(); if (_pagination.PageIndex != localPlayerPageIndexFromPillar) { _pagination.PageIndex = localPlayerPageIndexFromPillar; UpdatePlayerPillars(); } UpdateCustomButtons(); }); _buttonPageDown.OnBtnPressCallback = Action<int>.op_Implicit((Action<int>)delegate { _pagination.PageDown(); UpdateCustomButtons(); }); _buttonPageUp.OnBtnPressCallback = Action<int>.op_Implicit((Action<int>)delegate { _pagination.PageUp(); UpdateCustomButtons(); }); })), (Action)null); } } [HarmonyPatch(typeof(CM_PageMap))] public static class CM_PageMapPatch { private static readonly Pagination _pagination = new Pagination(); private static CM_Item _buttonCenter = null; private static CM_Item _buttonPageUp = null; private static CM_Item _buttonPageDown = null; private static void OnPageChanged() { UpdateCustomButtons(); UpdateAllPlayerInventories(); } private static void UpdateCustomButtons() { _buttonPageUp.SetCoolButtonEnabled(_pagination.CanPageUp()); _buttonPageDown.SetCoolButtonEnabled(_pagination.CanPageDown()); _buttonCenter.SetText($"<color=white>P{_pagination.PageIndex + 1}</color>"); } [HarmonyPatch("Setup")] [HarmonyPostfix] public static void Setup__Postfix(CM_PageMap __instance) { CM_PageMap __instance2 = __instance; _pagination.OnPageChanged += OnPageChanged; CoroutineManager.StartCoroutine(CollectionExtensions.WrapToIl2Cpp(CoroutineHelpers.NextFrame(delegate { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_0064: 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) //IL_008b: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("LobbyExpansion_PageButtonRoot"); val.transform.SetParent(((Component)__instance2.m_btnGotoObjectives).transform); val.transform.localPosition = new Vector3(40f, -200f, 0f); val.transform.localScale = Vector3.one * 0.6f; _buttonCenter = CoolButton.InstantiateSquareButton(val.transform, Vector3.zero); _buttonPageDown = CoolButton.InstantiateSquareButton(val.transform, new Vector3(-40f, 80f, 0f), hideText: true, displayArrow: true); ((Component)_buttonPageDown).transform.localRotation = Quaternion.Euler(0f, 0f, 90f); _buttonPageUp = CoolButton.InstantiateSquareButton(val.transform, new Vector3(-40f, -160f, 0f), hideText: true, displayArrow: true, flipArrow: true); ((Component)_buttonPageUp).transform.localRotation = Quaternion.Euler(0f, 0f, 90f); UpdateCustomButtons(); _buttonCenter.OnBtnPressCallback = Action<int>.op_Implicit((Action<int>)delegate { int localPlayerPageFromSlotIndex = Pagination.GetLocalPlayerPageFromSlotIndex(); if (_pagination.PageIndex != localPlayerPageFromSlotIndex) { _pagination.PageIndex = localPlayerPageFromSlotIndex; UpdateAllPlayerInventories(); } UpdateCustomButtons(); }); _buttonPageDown.OnBtnPressCallback = Action<int>.op_Implicit((Action<int>)delegate { _pagination.PageDown(); }); _buttonPageUp.OnBtnPressCallback = Action<int>.op_Implicit((Action<int>)delegate { _pagination.PageUp(); }); })), (Action)null); } private static void UpdateAllPlayerInventories() { CM_PageMap current = CM_PageMap.Current; int num = 0; Enumerator<SNet_Player> enumerator = SNet.Slots.SlottedPlayers.GetEnumerator(); while (enumerator.MoveNext()) { SNet_Player current2 = enumerator.Current; if (current2.IsInSlot) { current.UpdatePlayerInventory(current2, num); num++; } } } [HarmonyPatch("Update")] [HarmonyPostfix] public static void Update__Postfix() { if (Input.GetKeyDown((KeyCode)281)) { _pagination.PageDown(); } if (Input.GetKeyDown((KeyCode)280)) { _pagination.PageUp(); } } [HarmonyPatch("UpdatePlayerInventory")] [HarmonyPostfix] public static void UpdatePlayerInventory__Postfix(CM_PageMap __instance, SNet_Player player, int count) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0021: 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) PUI_Inventory val = ((Il2CppArrayBase<PUI_Inventory>)(object)__instance.m_inventory)[player.PlayerSlotIndex()]; Vector2 position = ((RectTransformComp)val).GetPosition(); Vector2 position2 = default(Vector2); ((Vector2)(ref position2))..ctor(position.x, position.y); int num = 0; for (int num2 = count; num2 > 3; num2 -= 4) { num++; } if (_pagination.PageIndex != num) { position2.x = 5000f; } position2.y = -150f + (float)(count % 4) * (0f - __instance.m_inventoryOffsetPerPlayer); ((RectTransformComp)val).SetPosition(position2); } } [HarmonyPatch(typeof(CM_PlayerLobbyBar))] public static class CM_PlayerLobbyBarPatch { [HarmonyPatch("SpawnPlayerModel")] [HarmonyPrefix] public static bool SpawnPlayerModel__Prefix(CM_PlayerLobbyBar __instance, ref int index) { if (index > 3) { int num = index % 4; index = num; } return true; } } [HarmonyPatch] public static class CP_Bioscan_CorePatch { } [HarmonyPatch(typeof(CP_PlayerScanner))] public static class CP_PlayerScannerPatch { [HarmonyPatch("StartScan")] [HarmonyPrefix] public static bool StartScan__Prefix(CP_PlayerScanner __instance) { if (((Il2CppArrayBase<float>)(object)__instance.m_scanSpeeds).Length < PluginConfig.MaxPlayers) { Il2CppStructArray<float> scanSpeeds = __instance.m_scanSpeeds; __instance.m_scanSpeeds = new Il2CppStructArray<float>((long)PluginConfig.MaxPlayers); for (int i = 0; i < PluginConfig.MaxPlayers; i++) { ((Il2CppArrayBase<float>)(object)__instance.m_scanSpeeds)[i] = ((Il2CppArrayBase<float>)(object)scanSpeeds)[Math.Min(i, ((Il2CppArrayBase<float>)(object)scanSpeeds).Length - 1)]; } } return true; } } [HarmonyPatch(typeof(DefaultCharacterLayouts))] public class DefaultCharacterLayoutsPatch { [HarmonyPatch("GetDefaultVanityItems")] [HarmonyPriority(600)] [HarmonyPrefix] public static bool GetDefaultVanityItems__Prefix(ref int characterIndex) { if (characterIndex > 3) { characterIndex %= 4; } return true; } } [HarmonyPatch(typeof(DiscordManager))] public class DiscordManagerPatch { [HarmonyPatch("GetCharacterNickname")] [HarmonyPostfix] public static void GetCharacterNickname__Postfix(ref string __result, int characterIndex) { if (characterIndex > 3) { __result = PluginConfig.GetExtraSlotNickname(characterIndex); } } } [HarmonyPatch(typeof(DramaManager))] public static class DramaManagerPatch { [HarmonyPatch("Setup")] [HarmonyPostfix] public static void Setup__Postfix() { ResetDramaFieldsProperly(); } [HarmonyPatch("OnLevelCleanup")] [HarmonyPostfix] public static void OnLevelCleanup__Postfix() { ResetDramaFieldsProperly(); } private static void ResetDramaFieldsProperly() { DramaManager.SyncedPlayerStates = new Il2CppStructArray<DRAMA_State>((long)PluginConfig.MaxPlayers); DramaManager.SyncedPlayerTensions = new Il2CppStructArray<float>((long)PluginConfig.MaxPlayers); for (int i = 0; i < ((Il2CppArrayBase<DRAMA_State>)(object)DramaManager.SyncedPlayerStates).Length; i++) { ((Il2CppArrayBase<DRAMA_State>)(object)DramaManager.SyncedPlayerStates)[i] = (DRAMA_State)0; } } } [HarmonyPatch(typeof(ElevatorCage))] public static class ElevatorCagePatch { [HarmonyPatch("SkipPreReleaseSequence")] [HarmonyPrefix] [HarmonyWrapSafe] public static bool SkipPreReleaseSequence__Prefix(ElevatorCage __instance, CellSoundPlayer sound, ref int playerId) { if ((Object)(object)((Il2CppArrayBase<ElevatorSeat>)(object)__instance.m_seatsFromShaft)[playerId] == (Object)null) { L.Warning($"playerId {playerId} has a null seat. Skipping call."); return false; } return true; } [HarmonyPatch("RegisterSpawnPoints")] [HarmonyPrefix] [HarmonyWrapSafe] public static bool RegisterSpawnPoints__Prefix(ElevatorCage __instance) { __instance.m_spawnPoints = new Il2CppReferenceArray<PlayerSpawnpoint>((long)PluginConfig.MaxPlayers); for (int i = 0; i < PluginConfig.MaxPlayers; i++) { int num = i % 4; ((Il2CppArrayBase<PlayerSpawnpoint>)(object)__instance.m_spawnPoints)[i] = PlayerManager.RegisterSpawnpoint((PlayerspawnpointType)0, i, ((Il2CppArrayBase<ElevatorSeat>)(object)__instance.m_seatsFromShaft)[num]); } return false; } [HarmonyPatch("PlaySeatOpenStraps")] [HarmonyPrefix] [HarmonyWrapSafe] public static bool PlaySeatOpenStraps__Prefix(CellSoundPlayer sound, int playerId, bool isLocal) { if (playerId > 3) { return false; } return true; } } [HarmonyPatch(typeof(ElevatorRide))] public static class ElevatorRidePatch { [HarmonyPatch("StartPreReleaseSequence")] [HarmonyPrefix] [HarmonyWrapSafe] public static bool StartPreReleaseSequence__Prefix(Action onDone) { return true; } [HarmonyPatch("Cleanup")] [HarmonyPrefix] [HarmonyWrapSafe] public static bool Cleanup__Prefix() { return true; } [HarmonyPatch("SpawnShaftSegments")] [HarmonyPostfix] [HarmonyWrapSafe] public static void SpawnShaftSegments__Postfix(ElevatorRide __instance) { ElevatorRide __instance2 = __instance; ElevatorShaftTop shaftTop = __instance2.m_shaftTop; Il2CppReferenceArray<ElevatorSeat> elevatorSeats = shaftTop.m_elevatorSeats; shaftTop.m_elevatorSeats = new Il2CppReferenceArray<ElevatorSeat>((long)PluginConfig.MaxPlayers); for (int i = 0; i < PluginConfig.MaxPlayers; i++) { int num = i % 4; ((Il2CppArrayBase<ElevatorSeat>)(object)shaftTop.m_elevatorSeats)[i] = ((Il2CppArrayBase<ElevatorSeat>)(object)elevatorSeats)[num]; } Il2CppReferenceArray<Animator> hSULoadingArmAnims = shaftTop.m_HSULoadingArmAnims; shaftTop.m_HSULoadingArmAnims = new Il2CppReferenceArray<Animator>((long)PluginConfig.MaxPlayers); for (int j = 0; j < PluginConfig.MaxPlayers; j++) { int num2 = j % 4; ((Il2CppArrayBase<Animator>)(object)shaftTop.m_HSULoadingArmAnims)[j] = ((Il2CppArrayBase<Animator>)(object)hSULoadingArmAnims)[num2]; } ((MonoBehaviour)__instance2).StartCoroutine(CollectionExtensions.WrapToIl2Cpp(CoroutineHelpers.NextFrame(delegate { ElevatorCage elevatorCage = __instance2.m_elevatorCage; Il2CppReferenceArray<Transform> hSUAligns = elevatorCage.m_HSUAligns; elevatorCage.m_HSUAligns = new Il2CppReferenceArray<Transform>((long)PluginConfig.MaxPlayers); for (int k = 0; k < PluginConfig.MaxPlayers; k++) { int num3 = k % 4; ((Il2CppArrayBase<Transform>)(object)elevatorCage.m_HSUAligns)[k] = ((Il2CppArrayBase<Transform>)(object)hSUAligns)[num3]; } }))); } [HarmonyPatch("Cleanup")] [HarmonyPostfix] [HarmonyWrapSafe] public static void Cleanup__Postfix() { if (ElevatorRide.ElevatorRideInProgress) { ElevatorRide.ElevatorRideInProgress = false; ElevatorRide.Current.m_shaftTop.Cleanup(); } } } [HarmonyPatch(typeof(ElevatorSeat))] public class ElevatorSeatPatch { private static int _frame; [HarmonyPatch("SkipPreReleaseSequence")] [HarmonyPostfix] [HarmonyWrapSafe] public static void SkipPreReleaseSequence__Postfix(CellSoundPlayer sound) { CellSoundPlayer sound2 = sound; sound2.Stop(); int frameCount = Time.frameCount; if (_frame != frameCount) { CoroutineManager.StartCoroutine(CollectionExtensions.WrapToIl2Cpp(CoroutineHelpers.NextFrame(delegate { sound2.Post(EVENTS.PLAY_15_ELEVATOR_RELEASE, true); })), (Action)null); } _frame = frameCount; } } [HarmonyPatch(typeof(_PreReleaseSequence_d__33))] public class ElevatorSeatPatchTwo { private static ElevatorSeat _localSeat; [HarmonyPatch("MoveNext")] [HarmonyPostfix] [HarmonyWrapSafe] public static void ElevatorSeat___PreReleaseSequence_d__33__MoveNext__Postfix(_PreReleaseSequence_d__33 __instance) { if (__instance.isLocal) { _localSeat = __instance.__4__this; } if (((Il2CppObjectBase)__instance.__4__this).Pointer == ((Il2CppObjectBase)_localSeat).Pointer) { __instance.isLocal = true; } } } [HarmonyPatch(typeof(EnemyAgent))] public class EnemyAgentArenaDimensionPatch { [HarmonyPatch("GetArenaDimension")] [HarmonyPrefix] public static void GetArenaDimension__Prefix(ref uint slotIndex) { slotIndex %= 4u; } } [HarmonyPatch(typeof(GearManager))] public static class GearManagerPatch { [HarmonyPatch("Setup")] [HarmonyPostfix] public static void Setup__Postfix() { BotFavoritesData botFavoritesData = GearManager.BotFavoritesData; Il2CppStringArray original = botFavoritesData.LastEquipped_Melee; if (Expand(ref original)) { botFavoritesData.LastEquipped_Melee = original; } Il2CppStringArray original2 = botFavoritesData.LastEquipped_Standard; if (Expand(ref original2)) { botFavoritesData.LastEquipped_Standard = original2; } Il2CppStringArray original3 = botFavoritesData.LastEquipped_Special; if (Expand(ref original3)) { botFavoritesData.LastEquipped_Special = original3; } Il2CppStringArray original4 = botFavoritesData.LastEquipped_Class; if (Expand(ref original4)) { botFavoritesData.LastEquipped_Class = original4; } Il2CppStringArray original5 = botFavoritesData.LastEquipped_HackingTool; if (Expand(ref original5)) { botFavoritesData.LastEquipped_HackingTool = original5; } } private static bool Expand(ref Il2CppStringArray original) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown if (((Il2CppArrayBase<string>)(object)original).Length >= PluginConfig.MaxPlayers) { return false; } Il2CppStringArray val = original; Il2CppStringArray val2 = new Il2CppStringArray((long)PluginConfig.MaxPlayers); for (int i = 0; i < ((Il2CppArrayBase<string>)(object)val2).Length; i++) { if (i < ((Il2CppArrayBase<string>)(object)val).Length) { ((Il2CppArrayBase<string>)(object)val2)[i] = ((Il2CppArrayBase<string>)(object)val)[i]; } else { ((Il2CppArrayBase<string>)(object)val2)[i] = string.Empty; } } original = val2; return true; } } [HarmonyPatch(typeof(PlayerAgent))] public static class PlayerAgentPatch { [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPrefix] public static bool PlayerCharacterFilter__Getter__Prefix(PlayerAgent __instance, ref DialogCharFilter __result) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected I4, but got Unknown int characterID = __instance.CharacterID; if (characterID > 3) { int num = characterID % 4; __result = (DialogCharFilter)(int)((Il2CppArrayBase<DialogCharFilter>)(object)__instance.m_playerCharacters)[num]; return false; } return true; } } [HarmonyPatch(typeof(PlayerCoverageSystem))] public static class PlayerCoverageSystemPatch { [HarmonyPatch("Awake")] [HarmonyPostfix] public static void Awake__Postfix() { if (((Il2CppArrayBase<int>)(object)PlayerCoverageSystem.s_coverageKeys).Length < PluginConfig.MaxPlayers) { PlayerCoverageSystem.s_coverageKeys = new Il2CppStructArray<int>((long)PluginConfig.MaxPlayers); } } [HarmonyPatch("GetCoverageKey", new Type[] { typeof(int) })] [HarmonyPrefix] public static bool GetCoverageKey__Prefix(ref int __result, int activeID) { if (activeID < 0) { return true; } if (activeID >= ((Il2CppArrayBase<int>)(object)PlayerCoverageSystem.s_coverageKeys).Length) { L.Error($"{"activeID"} was greater than the size of s_coverageKeys ({((Il2CppArrayBase<int>)(object)PlayerCoverageSystem.s_coverageKeys).Length})."); return true; } __result = ((Il2CppArrayBase<int>)(object)PlayerCoverageSystem.s_coverageKeys)[activeID]; return false; } } [HarmonyPatch(typeof(PlayerCoverageDataSet_Portal))] public static class PlayerCoverageDataSet_PortalPatch { [HarmonyPatch("SetupData")] [HarmonyPostfix] public static void SetupData__Postfix(PlayerCoverageDataSet_Portal? __instance) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown L.Assert(__instance != null, "instance was null"); __instance.m_coverageDatas = new Il2CppReferenceArray<PlayerCoverageData>((long)PluginConfig.MaxPlayers); for (int i = 0; i < ((Il2CppArrayBase<PlayerCoverageData>)(object)__instance.m_coverageDatas).Length; i++) { ((Il2CppArrayBase<PlayerCoverageData>)(object)__instance.m_coverageDatas)[i] = new PlayerCoverageData(); } } } [HarmonyPatch(typeof(PlayerDialogManager))] public static class PlayerDialogManagerPatch { [HarmonyPatch("WantToStartDialog")] [HarmonyPatch(new Type[] { typeof(uint), typeof(PlayerAgent) })] [HarmonyPrefix] [HarmonyWrapSafe] public static bool WantToStartDialog__Prefix(uint dialogID, PlayerAgent source) { if ((Object)(object)source == (Object)null) { return false; } return true; } } [HarmonyPatch(typeof(PlayerManager))] public static class PlayerManagerPatch { private static readonly Random _random = new Random(690420); [HarmonyPatch("GetSpawnPoint")] [HarmonyPrefix] public static bool GetSpawnPoint__Prefix(PlayerspawnpointType type, ref int referenceID) { if (referenceID > 3) { int num = referenceID % 4; referenceID = num; } return true; } [HarmonyPatch("Awake")] [HarmonyPostfix] public static void Awake__Postfix(PlayerManager? __instance) { L.Assert((Object)(object)__instance != (Object)null, "__instance was null"); L.Assert(((Il2CppArrayBase<List<PositionReservation>>)(object)__instance.BotAIData.PositionReservations).Length == PluginConfig.MaxPlayers, $"{"PositionReservations"} was {((Il2CppArrayBase<List<PositionReservation>>)(object)__instance.BotAIData.PositionReservations).Length} when the manual patch should have set it to {PluginConfig.MaxPlayers}."); L.Assert(((Il2CppArrayBase<List<ObjectReservation>>)(object)__instance.BotAIData.ObjectReservations).Length == PluginConfig.MaxPlayers, $"{"ObjectReservations"} was {((Il2CppArrayBase<List<ObjectReservation>>)(object)__instance.BotAIData.ObjectReservations).Length} when the manual patch should have set it to {PluginConfig.MaxPlayers}."); for (int i = 4; i < PluginConfig.MaxPlayers; i++) { ((Il2CppArrayBase<List<PositionReservation>>)(object)__instance.BotAIData.PositionReservations)[i] = new List<PositionReservation>((int)PluginConfig.MaxPlayers); ((Il2CppArrayBase<List<ObjectReservation>>)(object)__instance.BotAIData.ObjectReservations)[i] = new List<ObjectReservation>((int)PluginConfig.MaxPlayers); } } [HarmonyPatch("Setup")] [HarmonyPostfix] public static void Setup__Postfix(PlayerManager __instance) { L.Assert((Object)(object)__instance != (Object)null, "__instance was null"); FixAvailableSpawnpoints(__instance); FixPlayerColors(__instance); } private static Color GenerateSeededRandomColor(float saturation = 0.8f, float value = 0.8f) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) return Color.HSVToRGB(_random.NextSingle(), saturation, value); } private static void FixPlayerColors(PlayerManager __instance) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_0089: Unknown result type (might be due to invalid IL or missing references) Color[] array = (Color[])(object)new Color[4] { ColorExt.Hex("FFA500"), Color.yellow, Color.magenta, Color.white }; Il2CppStructArray<Color> playerColors = __instance.m_playerColors; __instance.m_playerColors = new Il2CppStructArray<Color>((long)PluginConfig.MaxPlayers); for (int i = 0; i < PluginConfig.MaxPlayers; i++) { Color val = ((i < 4) ? ((Il2CppArrayBase<Color>)(object)playerColors)[i] : ((i >= 8) ? GenerateSeededRandomColor() : array[i % 4])); Color val2 = val; ((Il2CppArrayBase<Color>)(object)__instance.m_playerColors)[i] = val2; } } private static void FixAvailableSpawnpoints(PlayerManager playerManager) { int length = Enum.GetValues(typeof(PlayerspawnpointType)).Length; if (length != 5) { L.Warning($"{"PlayerspawnpointType"} contained {length} types, but {5} were expected. This may or may not work as expected!"); } for (int i = 0; i < length; i++) { ((Il2CppArrayBase<Il2CppReferenceArray<PlayerSpawnpoint>>)(object)playerManager.m_availableSpawnpoints)[i] = new Il2CppReferenceArray<PlayerSpawnpoint>((long)PluginConfig.MaxPlayers); } } } [HarmonyPatch(typeof(PlayerVoiceManager))] public static class PlayerVoiceManagerPatch { [HarmonyPatch("Setup")] [HarmonyPostfix] public static void Setup__Postfix(PlayerVoiceManager __instance) { if (((Il2CppArrayBase<PlayerVoice>)(object)__instance.m_playerVoices).Length < PluginConfig.MaxPlayers) { __instance.m_playerVoices = new Il2CppReferenceArray<PlayerVoice>((long)PluginConfig.MaxPlayers); } } } [HarmonyPatch(typeof(PUI_Compass))] public static class PUI_CompassPatch { [HarmonyPatch("Setup")] [HarmonyPostfix] public static void Setup__Postfix(PUI_Compass __instance) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) __instance.m_playerPingMarkers = new Il2CppReferenceArray<NavMarker>((long)PluginConfig.MaxPlayers); __instance.m_playerNameMarkers = new Il2CppReferenceArray<NavMarker>((long)PluginConfig.MaxPlayers); __instance.m_playerMarkersWorldPos = new Il2CppStructArray<Vector3>((long)PluginConfig.MaxPlayers); __instance.m_playerPingMarkersActive = new Il2CppStructArray<bool>((long)PluginConfig.MaxPlayers); __instance.m_playerNameMarkersVisible = new Il2CppStructArray<bool>((long)PluginConfig.MaxPlayers); for (int i = 0; i < PluginConfig.MaxPlayers; i++) { ((Il2CppArrayBase<NavMarker>)(object)__instance.m_playerPingMarkers)[i] = __instance.SpawnCompassObj(__instance.m_playerMarkerPrefab, 0f, 0f, false).GetComponent<NavMarker>(); ((Component)((Il2CppArrayBase<NavMarker>)(object)__instance.m_playerPingMarkers)[i]).transform.localEulerAngles = new Vector3(0f, 0f, 180f); ((Component)((Il2CppArrayBase<NavMarker>)(object)__instance.m_playerPingMarkers)[i]).transform.localScale = new Vector3(__instance.m_navMarkerScale, __instance.m_navMarkerScale, __instance.m_navMarkerScale); ((Il2CppArrayBase<NavMarker>)(object)__instance.m_playerPingMarkers)[i].SetVisible(false); ((Il2CppArrayBase<NavMarker>)(object)__instance.m_playerPingMarkers)[i].SetPinEnabled(true); ((Il2CppArrayBase<NavMarker>)(object)__instance.m_playerNameMarkers)[i] = __instance.SpawnCompassObj(__instance.m_playerMarkerPrefab, 0f, 0f, false).GetComponent<NavMarker>(); ((Component)((Il2CppArrayBase<NavMarker>)(object)__instance.m_playerNameMarkers)[i]).transform.localScale = new Vector3(__instance.m_navMarkerScale, __instance.m_navMarkerScale, __instance.m_navMarkerScale); ((Il2CppArrayBase<NavMarker>)(object)__instance.m_playerNameMarkers)[i].SetStyle((eNavMarkerStyle)12); ((Il2CppArrayBase<NavMarker>)(object)__instance.m_playerNameMarkers)[i].SetState((NavMarkerState)1); ((Il2CppArrayBase<NavMarker>)(object)__instance.m_playerNameMarkers)[i].SetVisible(false); ((Il2CppArrayBase<NavMarker>)(object)__instance.m_playerNameMarkers)[i].SetPinEnabled(false); ((Il2CppArrayBase<bool>)(object)__instance.m_playerPingMarkersActive)[i] = false; } } } [HarmonyPatch(typeof(SNet_Core))] public static class SNet_CorePatch { [HarmonyPatch("GetBotNickname")] [HarmonyPostfix] public static void GetBotNickname__Postfix(ref string __result, int characterIndex) { if (characterIndex > 3) { __result = PluginConfig.GetExtraSlotNickname(characterIndex); } } } [HarmonyPatch(typeof(SNet_LobbyManager))] public class SNet_LobbyManagerPatch { [HarmonyPatch("CreateLobby")] [HarmonyPrefix] public static bool CreateLobby__Prefix(SNet_LobbySettings settings, bool leaveSessionHub) { if (settings.m_playerLimit < PluginConfig.MaxPlayers) { settings.m_playerLimit = PluginConfig.MaxPlayers; } return true; } } [HarmonyPatch(typeof(SNet_PlayerSlotManager))] public static class SNet_PlayerSlotManagerPatch { [HarmonyPatch("Setup")] [HarmonyPostfix] public static void Setup__Postfix(SNet_PlayerSlotManager __instance) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) __instance.PlayerSlots = new Il2CppReferenceArray<SNet_Slot>((long)PluginConfig.MaxPlayers); __instance.CharacterSlots = new Il2CppReferenceArray<SNet_Slot>((long)PluginConfig.MaxPlayers); __instance.m_playerSlotPermissions = new Il2CppStructArray<SlotPermission>((long)PluginConfig.MaxPlayers); for (int i = 0; i < PluginConfig.MaxPlayers; i++) { ((Il2CppArrayBase<SNet_Slot>)(object)__instance.PlayerSlots)[i] = new SNet_Slot(i); ((Il2CppArrayBase<SNet_Slot>)(object)__instance.CharacterSlots)[i] = new SNet_Slot(i); __instance.InternalSetSlotPermission(i, (SlotPermission)0, true); if (i > 3) { ((Il2CppArrayBase<SlotPermission>)(object)__instance.m_playerSlotPermissions)[i] = PluginConfig.GetExtraSlotPermission(i); } } } } [HarmonyPatch(typeof(SNet_SessionHub))] public static class SNet_SessionHubPatch { [HarmonyPatch("TryAddBotToSession")] [HarmonyPostfix] public static void TryAddBotToSession__Postfix(SNet_SessionHub __instance, ref bool __result, SNet_Player bot) { if (!__result && bot.IsBot && SNet.IsMaster && __instance.PlayersInSession.Count <= PluginConfig.MaxPlayers - 1 && !__instance.PlayersInSession.Contains(bot)) { __instance.AddPlayerToSession(bot, true); __result = true; } } } [HarmonyPatch(typeof(SteamMatchmaking))] public static class SteamMatchmakingPatch { [HarmonyPatch("CreateLobby")] [HarmonyPrefix] public static bool CreateLobby__Prefix(ELobbyType eLobbyType, ref int cMaxMembers) { if (cMaxMembers < PluginConfig.MaxPlayers) { cMaxMembers = PluginConfig.MaxPlayers; } return true; } } } namespace GTFO.LobbyExpansion.Compatibility { public class ChatterRebornPatch : ModCompatibilityPatch { public const string PluginGuid = "CHTR"; private Type? _dramaChatterManagerType; private Type? _dramaChatterMachineType; private Type? _enemyDetectionManagerType; private Type? _enemyDramaBehaviorType; private FieldInfo? _m_playerVisiblityField; private FieldInfo? _m_detectedPlayers; public static ChatterRebornPatch Instance { get; } = new ChatterRebornPatch(); private ChatterRebornPatch() { } public override bool ShouldApply() { return BepInExUtil.IsPluginLoaded("CHTR"); } public override void Apply(Harmony harmony) { Assembly assembly = BepInExUtil.GetPluginInstance("CHTR").GetType().Assembly; _dramaChatterManagerType = ReflectionUtil.GetRequiredTypeByName("DramaChatterManager", assembly); _dramaChatterMachineType = ReflectionUtil.GetRequiredTypeByName("DramaChatterMachine", assembly); _enemyDetectionManagerType = ReflectionUtil.GetRequiredTypeByName("EnemyDetectionManager", assembly); _enemyDramaBehaviorType = ReflectionUtil.GetRequiredTypeByName("EnemyDramaBehavior", assembly); _m_playerVisiblityField = AccessTools.Field(_enemyDramaBehaviorType, "m_playerVisiblity"); L.Assert((object)_m_playerVisiblityField != null, "_m_playerVisiblityField is null."); _m_detectedPlayers = AccessTools.Field(_enemyDramaBehaviorType, "m_detectedPlayers"); L.Assert((object)_m_detectedPlayers != null, "_m_detectedPlayers is null."); FixFieldsAndProperties(); ApplyPatches(harmony); } protected void FixFieldsAndProperties() { object value = (_enemyDetectionManagerType.GetProperty("Current", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy) ?? throw new Exception("Unable to find detectionManagerCurrentProperty.")).GetValue(null); if (value == null) { throw new Exception("detectionManager current instance was null."); } object value2 = (_dramaChatterManagerType.GetProperty("Current", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy) ?? throw new Exception("Unable to find dramaChatterManagerCurrentProperty in _dramaChatterManagerType.")).GetValue(null); if (value2 == null) { throw new Exception("dramaChatterManager current instance was null."); } PropertyInfo? obj = _dramaChatterManagerType.GetProperty("PlayerDramaMachines", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public) ?? throw new Exception("Unable to find PlayerDramaMachines property"); Array value3 = Array.CreateInstance(_dramaChatterMachineType, PluginConfig.MaxPlayers); obj.SetValue(value2, value3); (_dramaChatterManagerType.GetField("_allow_participation", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new Exception("Unable to find _allow_participation field")).SetValue(value2, new bool[PluginConfig.MaxPlayers]); (_enemyDetectionManagerType.GetField("m_enemyScores", BindingFlags.Instance | BindingFlags.Public) ?? throw new Exception("Unable to find m_enemyScoresField.")).SetValue(value, new float[PluginConfig.MaxPlayers]); (_enemyDetectionManagerType.GetField("m_enemyVisibilites", BindingFlags.Instance | BindingFlags.Public) ?? throw new Exception("Unable to find m_enemyVisibilitesField.")).SetValue(value, new int[PluginConfig.MaxPlayers]); } protected void ApplyPatches(Harmony harmony) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown harmony.PatchAll(typeof(ChatterRebornPatch)); MethodInfo methodInfo = AccessTools.Method(_enemyDramaBehaviorType, "Awake", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(ChatterRebornPatch), "EnemyDramaBehavior__Awake__Postfix", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } [HarmonyPatch(typeof(StartMainGame), "Start")] [HarmonyWrapSafe] [HarmonyPostfix] [HarmonyPriority(200)] private static void StartMainGame__Start__Postfix() { Instance.FixFieldsAndProperties(); } [HarmonyWrapSafe] private static void EnemyDramaBehavior__Awake__Postfix(object __instance) { if ((object)Instance._enemyDramaBehaviorType == null) { L.Error("Awake postfix can't run; _enemyDramaBehaviorType is null."); return; } if (!Instance._enemyDramaBehaviorType.IsInstanceOfType(__instance)) { L.Error("Awake postfix was passed an instance that is NOT an instance of _enemyDramaBehaviorType type? It was of type " + __instance.GetType().FullName); return; } if ((object)Instance._m_playerVisiblityField == null) { L.Error("Awake postfix can't run; _m_playerVisiblityField is null."); return; } if ((object)Instance._m_detectedPlayers == null) { L.Error("Awake postfix can't run; _m_detectedPlayers is null."); return; } Instance._m_playerVisiblityField.SetValue(__instance, new float[PluginConfig.MaxPlayers]); Instance._m_detectedPlayers.SetValue(__instance, new bool[PluginConfig.MaxPlayers]); } } public abstract class ModCompatibilityPatch { public abstract bool ShouldApply(); public abstract void Apply(Harmony harmony); } public class PacksHelperPatch : ModCompatibilityPatch { public const string PluginGuid = "Localia.PacksHelper"; public override bool ShouldApply() { return BepInExUtil.IsPluginLoaded("Localia.PacksHelper"); } public override void Apply(Harmony harmony) { Type type = BepInExUtil.GetPluginInstance("Localia.PacksHelper").GetType().Assembly.GetTypes().FirstOrDefault((Type t) => t.Name.Equals("PH_Manager", StringComparison.OrdinalIgnoreCase)); if ((object)type == null) { L.Error("Could not apply PacksHelper patch: managerType was null."); } else { PatchManagerType(type); } } protected static void PatchManagerType(Type managerType) { ReflectionUtil.SetStaticField(managerType, "health", new string[PluginConfig.MaxPlayers]); ReflectionUtil.SetStaticField(managerType, "standard", new string[PluginConfig.MaxPlayers]); ReflectionUtil.SetStaticField(managerType, "special", new string[PluginConfig.MaxPlayers]); ReflectionUtil.SetStaticField(managerType, "tool", new string[PluginConfig.MaxPlayers]); ReflectionUtil.SetStaticField(managerType, "ori_all_info", new string[PluginConfig.MaxPlayers]); ReflectionUtil.SetStaticField(managerType, "now_show_info", new string[PluginConfig.MaxPlayers]); } } } [CompilerGenerated] internal sealed class <>z__ReadOnlyArray<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { int ICollection.Count => _items.Length; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection<T>.Count => _items.Length; T IReadOnlyList<T>.this[int index] => _items[index]; int ICollection<T>.Count => _items.Length; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyArray(T[] items) { _items = items; } IEnumerato