using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
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 AIGraph;
using BepInEx;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BoosterImplants;
using CellMenu;
using ChainedPuzzles;
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.Collections.Generic;
using Microsoft.CodeAnalysis;
using Player;
using PlayerCoverage;
using SNetwork;
using Steamworks;
using UnityEngine;
[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.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+07a364f1460342f6136067a37d73c772adac1c0b")]
[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.0.1.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 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(bool condition, object data)
{
if (!condition)
{
string text = "ASSERTION FAILED: " + Format(data);
Fatal(text);
throw new ApplicationException(text);
}
}
internal static void DebugWarning(object data)
{
}
internal static void Info(object data)
{
Logger.LogMessage((object)Format(data));
}
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));
}
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;
}
string text = method.DeclaringType?.FullName ?? "???";
string name = method.Name;
string text2 = (string.IsNullOrWhiteSpace(parameterInfo) ? "" : (" (" + parameterInfo + ")"));
Verbose(text + "." + name + text2);
}
private static string Format(object msg)
{
return msg.ToString() ?? "";
}
}
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.0.1")]
public class Plugin : BasePlugin
{
private Harmony _harmony;
public override void Load()
{
//IL_017e: Unknown result type (might be due to invalid IL or missing references)
//IL_0188: Expected O, but got Unknown
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()
})
{
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);
}
L.Verbose("Applying manual patch " + item.GetType().Name + ".");
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;
}
L.Info("Loaded plugin GTFO.LobbyExpansion.");
}
}
public static class PluginConfig
{
public static readonly byte MaxPlayers = 8;
public static SlotPermission GetExtraSlotPermission(int slotIndex)
{
return (SlotPermission)4;
}
public static string GetExtraSlotNickname(int characterIndex)
{
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.0.1";
}
}
namespace GTFO.LobbyExpansion.Util
{
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 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);
}
L.Verbose("Applying \"" + patch.Description + "\" patch at " + ((IntPtr)num2).ToString("X"));
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 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__ReadOnlyArray<Patch>(new Patch[1]
{
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_PageLoadoutManualPatch : ManualPatch
{
protected override Type TargetType { get; } = typeof(CM_PageLoadout);
protected override void SetupPatches()
{
base.Patches.AddRange(new <>z__ReadOnlyArray<Patch>(new Patch[1]
{
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[12]
{
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 = "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__ReadOnlyArray<Patch>(new Patch[1]
{
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__ReadOnlyArray<Patch>(new Patch[1]
{
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__ReadOnlyArray<Patch>(new Patch[1]
{
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__ReadOnlyArray<Patch>(new Patch[1]
{
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__ReadOnlyArray<Patch>(new Patch[1]
{
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__ReadOnlyArray<Patch>(new Patch[1]
{
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__ReadOnlyArray<Patch>(new Patch[1]
{
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)
{
L.LogExecutingMethod();
if (((Il2CppArrayBase<PlayerBoosterImplantState>)(object)__instance.m_boosterPlayers).Length < PluginConfig.MaxPlayers)
{
L.Verbose("Expanding m_boosterPlayers size.");
__instance.m_boosterPlayers = new Il2CppReferenceArray<PlayerBoosterImplantState>((long)PluginConfig.MaxPlayers);
}
}
}
[HarmonyPatch(typeof(CM_PageExpeditionSuccess))]
public static class CM_PageExpeditionSuccessPatch
{
private static bool _pageDownDebounce;
private static bool _pageUpDebounce;
private static bool _needPositionUpdate;
private static DateTime _lastVisibilityUpdate = DateTime.Now;
public static int PageIndex { get; set; }
[HarmonyPatch("OnEnable")]
[HarmonyPostfix]
public static void OnEnable__Postfix(CM_PageExpeditionSuccess __instance)
{
L.LogExecutingMethod();
PageIndex = 0;
_needPositionUpdate = true;
UpdateVisiblePlayerReports(__instance);
}
[HarmonyPatch("Update")]
[HarmonyPostfix]
public static void Update__Postfix(CM_PageExpeditionSuccess __instance)
{
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
if (_needPositionUpdate)
{
L.Verbose("Updating position of extra player reports.");
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);
}
bool flag = false;
int num = (int)Math.Ceiling((double)(int)PluginConfig.MaxPlayers / 4.0) - 1;
if (PageIndex < num && !_pageDownDebounce && Input.GetKeyDown((KeyCode)281))
{
L.Verbose($"Showing next set of players {PageIndex}.");
PageIndex++;
_pageDownDebounce = true;
flag = true;
}
if (_pageDownDebounce && Input.GetKeyUp((KeyCode)281))
{
L.Verbose("Debounce off for page down.");
_pageDownDebounce = false;
}
if (PageIndex > 0 && !_pageUpDebounce && Input.GetKeyDown((KeyCode)280))
{
L.Verbose($"Showing previous set of players {PageIndex}.");
PageIndex--;
_pageUpDebounce = true;
flag = true;
}
if (_pageUpDebounce && Input.GetKeyUp((KeyCode)280))
{
L.Verbose("Debounce off for page up.");
_pageUpDebounce = false;
}
if (flag)
{
L.Verbose("Updating visible player reports.");
UpdateVisiblePlayerReports(__instance);
}
}
private static void UpdateVisiblePlayerReports(CM_PageExpeditionSuccess page)
{
if (page.m_playerReports == null)
{
return;
}
Il2CppReferenceArray<SNet_Slot> playerSlots = SNet.Slots.PlayerSlots;
int num = 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)
{
L.Verbose($"Hiding lobby bar at slot {i} since it is below the minimum visible index {num}.");
active = false;
}
else if (i >= num2)
{
L.Verbose($"Hiding lobby bar at slot {i} since it is above the maximum visible index {num2}.");
active = false;
}
else if (i >= ((Il2CppArrayBase<SNet_Slot>)(object)playerSlots).Count || (Object)(object)((Il2CppArrayBase<SNet_Slot>)(object)playerSlots)[i].player == (Object)null)
{
L.Verbose($"Hiding extra slot {i} since we don't have a player in that slot.");
active = false;
}
((Component)((Il2CppArrayBase<CM_PageSuccess_PrisonerEvaluation>)(object)page.m_playerReports)[i]).gameObject.SetActive(active);
}
}
}
}
[HarmonyPatch(typeof(CM_PageLoadout))]
public static class CM_PageLoadoutPatch
{
private static bool _pageDownDebounce;
private static bool _pageUpDebounce;
public static int PageIndex { get; set; }
[HarmonyPatch("Setup")]
[HarmonyPrefix]
public static bool Setup__Prefix(CM_PageLoadout __instance, MainMenuGuiLayer guiLayer)
{
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Expected O, but got Unknown
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
L.LogExecutingMethod();
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++)
{
string text = $"Player{j + 1}Root";
L.Verbose("Creating extra player root (" + text + ").");
GameObject val2 = new GameObject(text);
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_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: 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_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_0134: Unknown result type (might be due to invalid IL or missing references)
//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
//IL_028e: Unknown result type (might be due to invalid IL or missing references)
//IL_0269: Unknown result type (might be due to invalid IL or missing references)
L.LogExecutingMethod();
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++)
{
string text = $"Player{i + 1}Root";
L.Verbose("Updating extra player root position (" + text + ").");
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 = 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)
{
L.Verbose($"Hiding lobby bar at slot {j} since it is below the minimum visible index {num}.");
((Component)((Il2CppArrayBase<Transform>)(object)__instance.m_playerInfoHolders)[j]).gameObject.transform.position = new Vector3(5000f, 5000f, 5000f);
}
else if (j >= num2)
{
L.Verbose($"Hiding lobby bar at slot {j} since it is above the maximum visible index {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];
}
}
}
[HarmonyPatch("Update")]
[HarmonyPostfix]
public static void Update__Postfix(CM_PageLoadout __instance)
{
bool flag = false;
int num = (int)Math.Ceiling((double)(int)PluginConfig.MaxPlayers / 4.0) - 1;
if (PageIndex < num && !_pageDownDebounce && Input.GetKeyDown((KeyCode)281))
{
L.Verbose($"Showing next set of players {PageIndex}.");
PageIndex++;
_pageDownDebounce = true;
flag = true;
}
if (_pageDownDebounce && Input.GetKeyUp((KeyCode)281))
{
L.Verbose("Debounce off for page down.");
_pageDownDebounce = false;
}
if (PageIndex > 0 && !_pageUpDebounce && Input.GetKeyDown((KeyCode)280))
{
L.Verbose($"Showing previous set of players {PageIndex}.");
PageIndex--;
_pageUpDebounce = true;
flag = true;
}
if (_pageUpDebounce && Input.GetKeyUp((KeyCode)280))
{
L.Verbose("Debounce off for page up.");
_pageUpDebounce = false;
}
if (flag)
{
L.Verbose("Updating visible pillars.");
__instance.ArrangePlayerPillarSpacing();
}
}
[HarmonyPatch("ApplyPlayerSlotPermissionsFromSettings")]
[HarmonyPostfix]
public static void ApplyPlayerSlotPermissionsFromSettings__Postfix(CM_PageLoadout __instance)
{
//IL_0014: 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_0059: Unknown result type (might be due to invalid IL or missing references)
L.LogExecutingMethod();
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)
{
L.Verbose("Calling OnSlotsStatusChange.");
SNet.Core.OnSlotsStatusChanged();
}
if (SNet_Events.OnLobbyPermissionsSet != null)
{
L.Verbose("Calling OnLobbyPermissionsSet.");
SNet_Events.OnLobbyPermissionsSet.Invoke();
}
}
[HarmonyPatch("OnDisable")]
[HarmonyPostfix]
public static void OnDisable__Postfix()
{
L.LogExecutingMethod();
PageIndex = 0;
}
}
[HarmonyPatch(typeof(CM_PageMap))]
public static class CM_PageMapPatch
{
[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_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
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(0f, 0f);
int num = 0;
for (int num2 = count; num2 > 3; num2 -= 4)
{
num++;
}
float num3 = (0f - __instance.m_inventoryOffsetPerPlayer) * 1.3f;
position2.x = position.x + (float)num * num3;
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)
{
L.LogExecutingMethod($"{"index"}: {index}");
if (index > 3)
{
int num = index % 4;
L.Verbose($"Clamping {"index"} to {num}.");
index = num;
}
return true;
}
}
[HarmonyPatch(typeof(CP_PlayerScanner))]
public static class CP_PlayerScannerPatch
{
[HarmonyPatch("StartScan")]
[HarmonyPrefix]
public static bool StartScan__Prefix(CP_PlayerScanner __instance)
{
L.LogExecutingMethod();
if (((Il2CppArrayBase<float>)(object)__instance.m_scanSpeeds).Length < PluginConfig.MaxPlayers)
{
L.Verbose($"Expanding {"m_scanSpeeds"} size from {((Il2CppArrayBase<float>)(object)__instance.m_scanSpeeds).Length} to {PluginConfig.MaxPlayers} to account for more players being in the scan.");
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")]
[HarmonyPrefix]
public static bool GetDefaultVanityItems__Prefix(ref int characterIndex)
{
L.LogExecutingMethod($"{"characterIndex"}: {characterIndex}");
if (characterIndex > 3)
{
characterIndex %= 4;
L.Verbose($"Clamping {"characterIndex"} to {characterIndex}.");
}
return true;
}
}
[HarmonyPatch(typeof(DiscordManager))]
public class DiscordManagerPatch
{
[HarmonyPatch("GetCharacterNickname")]
[HarmonyPostfix]
public static void GetCharacterNickname__Postfix(ref string __result, int characterIndex)
{
L.LogExecutingMethod($"{"characterIndex"}: {characterIndex}, {"__result"}: {__result}");
if (characterIndex > 3)
{
__result = PluginConfig.GetExtraSlotNickname(characterIndex);
L.Verbose($"Corrected character nickname for index #{characterIndex} to {__result}.");
}
}
}
[HarmonyPatch(typeof(DramaManager))]
public static class DramaManagerPatch
{
[HarmonyPatch("Setup")]
[HarmonyPostfix]
public static void Setup__Postfix()
{
L.LogExecutingMethod();
ResetDramaFieldsProperly();
}
[HarmonyPatch("OnLevelCleanup")]
[HarmonyPostfix]
public static void OnLevelCleanup__Postfix()
{
L.LogExecutingMethod();
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]
public static bool SkipPreReleaseSequence__Prefix(ElevatorCage __instance, CellSoundPlayer sound, ref int playerId)
{
L.LogExecutingMethod($"{"playerId"}: {playerId}");
if (((Il2CppArrayBase<ElevatorSeat>)(object)__instance.m_seatsFromShaft).Length < PluginConfig.MaxPlayers)
{
L.Verbose($"Expanding {"m_seatsFromShaft"} size from {((Il2CppArrayBase<ElevatorSeat>)(object)__instance.m_seatsFromShaft).Length} to {PluginConfig.MaxPlayers}.");
Il2CppReferenceArray<ElevatorSeat> seatsFromShaft = __instance.m_seatsFromShaft;
__instance.m_seatsFromShaft = new Il2CppReferenceArray<ElevatorSeat>((long)PluginConfig.MaxPlayers);
for (int i = 0; i < ((Il2CppArrayBase<ElevatorSeat>)(object)seatsFromShaft).Length; i++)
{
int num = ((i <= 3) ? i : 0);
((Il2CppArrayBase<ElevatorSeat>)(object)__instance.m_seatsFromShaft)[i] = ((Il2CppArrayBase<ElevatorSeat>)(object)seatsFromShaft)[num];
}
}
if (playerId >= ((Il2CppArrayBase<ElevatorSeat>)(object)__instance.m_seatsFromShaft).Length)
{
L.Warning($"playerId {playerId} is past seats from shaft length: skipping call.");
return false;
}
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]
public static bool RegisterSpawnPoints__Prefix(ElevatorCage __instance)
{
L.LogExecutingMethod();
__instance.m_spawnPoints = new Il2CppReferenceArray<PlayerSpawnpoint>((long)PluginConfig.MaxPlayers);
for (int i = 0; i < PluginConfig.MaxPlayers; i++)
{
int num = ((i <= 3) ? i : 0);
((Il2CppArrayBase<PlayerSpawnpoint>)(object)__instance.m_spawnPoints)[i] = PlayerManager.RegisterSpawnpoint((PlayerspawnpointType)0, i, ((Il2CppArrayBase<ElevatorSeat>)(object)__instance.m_seatsFromShaft)[num]);
}
return false;
}
[HarmonyPatch("PlaySeatOpenStraps")]
[HarmonyPrefix]
public static bool PlaySeatOpenStraps__Prefix(CellSoundPlayer sound, int playerId, bool isLocal)
{
if (playerId > 3)
{
L.Verbose("Skipping PlaySeatOpenStraps for playerId > 3.");
return false;
}
return true;
}
}
[HarmonyPatch(typeof(GearManager))]
public static class GearManagerPatch
{
[HarmonyPatch("Setup")]
[HarmonyPostfix]
public static void Setup__Postfix()
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Expected O, but got Unknown
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Expected O, but got Unknown
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_010b: Expected O, but got Unknown
//IL_0176: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Expected O, but got Unknown
//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
//IL_01ef: Expected O, but got Unknown
L.Verbose("GearManager::Setup postfix");
BotFavoritesData botFavoritesData = GearManager.BotFavoritesData;
if (((Il2CppArrayBase<string>)(object)botFavoritesData.LastEquipped_Melee).Length < PluginConfig.MaxPlayers)
{
Il2CppStringArray lastEquipped_Melee = botFavoritesData.LastEquipped_Melee;
Il2CppStringArray val = new Il2CppStringArray((long)PluginConfig.MaxPlayers);
for (int i = 0; i < ((Il2CppArrayBase<string>)(object)val).Length; i++)
{
if (i < ((Il2CppArrayBase<string>)(object)lastEquipped_Melee).Length)
{
((Il2CppArrayBase<string>)(object)val)[i] = ((Il2CppArrayBase<string>)(object)lastEquipped_Melee)[i];
}
else
{
((Il2CppArrayBase<string>)(object)val)[i] = "";
}
}
botFavoritesData.LastEquipped_Melee = val;
}
if (((Il2CppArrayBase<string>)(object)botFavoritesData.LastEquipped_Standard).Length < PluginConfig.MaxPlayers)
{
Il2CppStringArray lastEquipped_Standard = botFavoritesData.LastEquipped_Standard;
Il2CppStringArray val2 = new Il2CppStringArray((long)PluginConfig.MaxPlayers);
for (int j = 0; j < ((Il2CppArrayBase<string>)(object)val2).Length; j++)
{
if (j < ((Il2CppArrayBase<string>)(object)lastEquipped_Standard).Length)
{
((Il2CppArrayBase<string>)(object)val2)[j] = ((Il2CppArrayBase<string>)(object)lastEquipped_Standard)[j];
}
else
{
((Il2CppArrayBase<string>)(object)val2)[j] = "";
}
}
botFavoritesData.LastEquipped_Standard = val2;
}
if (((Il2CppArrayBase<string>)(object)botFavoritesData.LastEquipped_Special).Length < PluginConfig.MaxPlayers)
{
Il2CppStringArray lastEquipped_Special = botFavoritesData.LastEquipped_Special;
Il2CppStringArray val3 = new Il2CppStringArray((long)PluginConfig.MaxPlayers);
for (int k = 0; k < ((Il2CppArrayBase<string>)(object)val3).Length; k++)
{
if (k < ((Il2CppArrayBase<string>)(object)lastEquipped_Special).Length)
{
((Il2CppArrayBase<string>)(object)val3)[k] = ((Il2CppArrayBase<string>)(object)lastEquipped_Special)[k];
}
else
{
((Il2CppArrayBase<string>)(object)val3)[k] = "";
}
}
botFavoritesData.LastEquipped_Special = val3;
}
if (((Il2CppArrayBase<string>)(object)botFavoritesData.LastEquipped_Class).Length < PluginConfig.MaxPlayers)
{
Il2CppStringArray lastEquipped_Class = botFavoritesData.LastEquipped_Class;
Il2CppStringArray val4 = new Il2CppStringArray((long)PluginConfig.MaxPlayers);
for (int l = 0; l < ((Il2CppArrayBase<string>)(object)val4).Length; l++)
{
if (l < ((Il2CppArrayBase<string>)(object)lastEquipped_Class).Length)
{
((Il2CppArrayBase<string>)(object)val4)[l] = ((Il2CppArrayBase<string>)(object)lastEquipped_Class)[l];
}
else
{
((Il2CppArrayBase<string>)(object)val4)[l] = "";
}
}
botFavoritesData.LastEquipped_Class = val4;
}
if (((Il2CppArrayBase<string>)(object)botFavoritesData.LastEquipped_HackingTool).Length >= PluginConfig.MaxPlayers)
{
return;
}
Il2CppStringArray lastEquipped_HackingTool = botFavoritesData.LastEquipped_HackingTool;
Il2CppStringArray val5 = new Il2CppStringArray((long)PluginConfig.MaxPlayers);
for (int m = 0; m < ((Il2CppArrayBase<string>)(object)val5).Length; m++)
{
if (m < ((Il2CppArrayBase<string>)(object)lastEquipped_HackingTool).Length)
{
((Il2CppArrayBase<string>)(object)val5)[m] = ((Il2CppArrayBase<string>)(object)lastEquipped_HackingTool)[m];
}
else
{
((Il2CppArrayBase<string>)(object)val5)[m] = "";
}
}
botFavoritesData.LastEquipped_HackingTool = val5;
}
}
[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_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Expected I4, but got Unknown
L.LogExecutingMethod();
int characterID = __instance.CharacterID;
if (characterID > 3)
{
int num = characterID % 4;
__result = (DialogCharFilter)(int)((Il2CppArrayBase<DialogCharFilter>)(object)__instance.m_playerCharacters)[num];
L.Verbose($"Clamping {"CharacterID"} from {characterID} to {num}.");
return false;
}
return true;
}
}
[HarmonyPatch(typeof(PlayerCoverageSystem))]
public static class PlayerCoverageSystemPatch
{
[HarmonyPatch("Awake")]
[HarmonyPostfix]
public static void Awake__Postfix()
{
L.LogExecutingMethod();
if (((Il2CppArrayBase<int>)(object)PlayerCoverageSystem.s_coverageKeys).Length < PluginConfig.MaxPlayers)
{
L.Verbose($"Expanding PlayerCoverageSystem::s_coverageKeys size from {((Il2CppArrayBase<int>)(object)PlayerCoverageSystem.s_coverageKeys).Length} to {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)
{
L.LogExecutingMethod();
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_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Expected O, but got Unknown
L.Verbose("PlayerCoverageDataSet_PortalPatch::SetupData__Postfix");
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++)
{
L.Verbose($"Instantiating PlayerCoverageData at index #{i} in m_coverageDatas.");
((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]
public static bool WantToStartDialog__Prefix(uint dialogID, PlayerAgent source)
{
L.LogExecutingMethod();
if ((Object)(object)source == (Object)null)
{
L.Verbose("Source was null.");
return false;
}
return true;
}
}
[HarmonyPatch(typeof(PlayerManager))]
public static class PlayerManagerPatch
{
[HarmonyPatch("GetSpawnPoint")]
[HarmonyPrefix]
public static bool GetSpawnPoint__Prefix(PlayerspawnpointType type, ref int referenceID)
{
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
L.Verbose($"{"PlayerManagerPatch"}::{"GetSpawnPoint__Prefix"} ({"type"}: {type}, {"referenceID"}: {referenceID})");
if (referenceID > 3)
{
int num = referenceID % 4;
L.Verbose($"{"GetSpawnPoint__Prefix"} changed referenceID from {referenceID} to {num}.");
referenceID = num;
}
return true;
}
[HarmonyPatch("Awake")]
[HarmonyPostfix]
public static void Awake__Postfix(PlayerManager? __instance)
{
L.Verbose("PlayerManagerPatch::Awake__Postfix");
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++)
{
L.Verbose($"Initializing BotAIData position and object reservation at index #{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.Verbose("PlayerManagerPatch::Setup__Postfix");
L.Assert((Object)(object)__instance != (Object)null, "__instance was null");
L.Verbose("Fixing available spawnpoints...");
FixAvailableSpawnpoints(__instance);
L.Verbose("Fixing player colors...");
FixPlayerColors(__instance);
}
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_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: 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 < ((Il2CppArrayBase<Color>)(object)playerColors).Length) ? ((Il2CppArrayBase<Color>)(object)playerColors)[i] : array[i % array.Length]);
L.Verbose($"Setting new player color at index #{i} to {val}.");
((Il2CppArrayBase<Color>)(object)__instance.m_playerColors)[i] = val;
}
L.Verbose($"m_playerColors now contains {((Il2CppArrayBase<Color>)(object)__instance.m_playerColors).Count} colors.");
}
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);
L.Verbose($"Set available spawnpoint at index #{i} to new max player size {PluginConfig.MaxPlayers}.");
}
}
}
[HarmonyPatch(typeof(PlayerVoiceManager))]
public static class PlayerVoiceManagerPatch
{
[HarmonyPatch("Setup")]
[HarmonyPostfix]
public static void Setup__Postfix(PlayerVoiceManager __instance)
{
L.Verbose("PlayerVoiceManager::Setup postfix");
if (((Il2CppArrayBase<PlayerVoice>)(object)__instance.m_playerVoices).Length < PluginConfig.MaxPlayers)
{
L.Verbose("Adjusting m_playerVoices size.");
__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_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
L.LogExecutingMethod();
__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++)
{
L.Verbose($"Setting up compass stuff at index #{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)
{
L.LogExecutingMethod();
if (settings.m_playerLimit < PluginConfig.MaxPlayers)
{
settings.m_playerLimit = PluginConfig.MaxPlayers;
L.Verbose($"Expanding m_playerLimit to {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_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Expected O, but got Unknown
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Expected O, but got Unknown
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
L.LogExecutingMethod();
__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)
{
L.LogExecutingMethod($"{"__result"}: {__result}");
if (!__result && bot.IsBot && SNet.IsMaster)
{
if (__instance.PlayersInSession.Count > PluginConfig.MaxPlayers - 1 || __instance.PlayersInSession.Contains(bot))
{
L.Verbose("No room to add another bot.");
return;
}
L.Verbose("Adding extra 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)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
L.LogExecutingMethod($"{eLobbyType}, {cMaxMembers}");
if (cMaxMembers < PluginConfig.MaxPlayers)
{
cMaxMembers = PluginConfig.MaxPlayers;
L.Verbose($"Expanding CreateLobby cMaxMembers to {PluginConfig.MaxPlayers}.");
}
return true;
}
}
}
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;
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_items).GetEnumerator();
}
void ICollection.CopyTo(Array array, int index)
{
((ICollection)_items).CopyTo(array, index);
}
int IList.Add(object? value)
{
throw new NotSupportedException();
}
void IList.Clear()
{
throw new NotSupportedException();
}
bool IList.Contains(object? value)
{
return ((IList)_items).Contains(value);
}
int IList.IndexOf(object? value)
{
return ((IList)_items).IndexOf(value);
}
void IList.Insert(int index, object? value)
{
throw new NotSupportedException();
}
void IList.Remove(object? value)
{
throw new NotSupportedException();
}
void IList.RemoveAt(int index)
{
throw new NotSupportedException();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return ((IEnumerable<T>)_items).GetEnumerator();
}
void ICollection<T>.Add(T item)
{
throw new NotSupportedException();
}
void ICollection<T>.Clear()
{
throw new NotSupportedException();
}
bool ICollection<T>.Contains(T item)
{
return ((ICollection<T>)_items).Contains(item);
}
void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
((ICollection<T>)_items).CopyTo(array, arrayIndex);
}
bool ICollection<T>.Remove(T item)
{
throw new NotSupportedException();
}
int IList<T>.IndexOf(T item)
{
return ((IList<T>)_items).IndexOf(item);
}
void IList<T>.Insert(int index, T item)
{
throw new NotSupportedException();
}
void IList<T>.RemoveAt(int index)
{
throw new NotSupportedException();
}
}