using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using HarmonyLib;
using Il2Cpp;
using Il2CppFusion;
using Il2CppFusion.Photon.Realtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSteamworks;
using Il2CppSystem.Collections;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using ShiftLobbyPlus;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Mod), "ShiftLobbyPlus", "1.0.0", "fzc", null)]
[assembly: MelonGame("Kwalee", "ShiftAtMidnight")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ShiftLobbyPlus")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ShiftLobbyPlus")]
[assembly: AssemblyTitle("ShiftLobbyPlus")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace ShiftLobbyPlus
{
public class Mod : MelonMod
{
private static MelonPreferences_Category _cat;
private static MelonPreferences_Entry<int> _maxPlayers;
public static Mod Instance;
public static int SelectedMax;
private static int _nextStatusTick;
public static int Target => Math.Clamp(_maxPlayers?.Value ?? 8, 1, 243);
public static void Log(string msg)
{
Mod instance = Instance;
if (instance != null)
{
((MelonBase)instance).LoggerInstance.Msg(msg);
}
}
public static void RaiseFusionPlayerSlots(string reason)
{
try
{
NetworkProjectConfig global = NetworkProjectConfig.Global;
SimulationConfig val = ((global != null) ? global.Simulation : null);
if (val != null && val.PlayerCount < Target)
{
Log($"[{reason}] Fusion Simulation.PlayerCount {val.PlayerCount} -> {Target}");
val.PlayerCount = Target;
}
}
catch (Exception ex)
{
Log("RaiseFusionPlayerSlots(" + reason + "): " + ex.Message);
}
}
public override void OnInitializeMelon()
{
Instance = this;
_cat = MelonPreferences.CreateCategory("ShiftLobbyPlus");
_maxPlayers = _cat.CreateEntry<int>("MaxPlayers", 8, (string)null, "Lobby max-players cap offered in the dropdown, 1-243 (game default: 3)", false, false, (ValueValidator)null, (string)null);
((MelonBase)this).LoggerInstance.Msg($"ShiftLobbyPlus init. MaxPlayers={Target}");
}
public override void OnUpdate()
{
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
if (Environment.TickCount < _nextStatusTick)
{
return;
}
_nextStatusTick = Environment.TickCount + 15000;
try
{
FusionNetworkManager instance = FusionNetworkManager.Instance;
NetworkRunner val = ((instance != null) ? instance.GetRunner() : null);
if ((Object)(object)val == (Object)null || !val.IsRunning)
{
return;
}
SessionInfo sessionInfo = val.SessionInfo;
string text = ((sessionInfo != null) ? $"Session '{sessionInfo.Name}' region={sessionInfo.Region} players={sessionInfo.PlayerCount}/{sessionInfo.MaxPlayers} open={sessionInfo.IsOpen}" : "Session info unavailable");
List<string> list = new List<string>();
IEnumerator<PlayerRef> enumerator = val.ActivePlayers.GetEnumerator();
IEnumerator val2 = ((Il2CppObjectBase)enumerator).Cast<IEnumerator>();
while (val2.MoveNext())
{
PlayerRef current = enumerator.Current;
double value = val.GetPlayerRtt(current) * 1000.0;
list.Add($"P{((PlayerRef)(ref current)).PlayerId}:{value:F0}ms");
}
if (list.Count > 0)
{
text = text + " | RTT " + string.Join(" ", list);
}
try
{
string text2 = text;
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(12, 1);
defaultInterpolatedStringHandler.AppendLiteral(" | simSlots=");
NetworkProjectConfig global = NetworkProjectConfig.Global;
int? value2;
if (global == null)
{
value2 = null;
}
else
{
SimulationConfig simulation = global.Simulation;
value2 = ((simulation != null) ? new int?(simulation.PlayerCount) : ((int?)null));
}
defaultInterpolatedStringHandler.AppendFormatted(value2);
text = text2 + defaultInterpolatedStringHandler.ToStringAndClear();
}
catch
{
}
((MelonBase)this).LoggerInstance.Msg(text);
}
catch (Exception ex)
{
((MelonBase)this).LoggerInstance.Warning("status probe: " + ex.Message);
}
}
public override void OnSceneWasLoaded(int buildIndex, string sceneName)
{
try
{
int s_MAXPLAYERS = PlatformManager.s_MAXPLAYERS;
if (s_MAXPLAYERS < Target)
{
PlatformManager.s_MAXPLAYERS = Target;
((MelonBase)this).LoggerInstance.Msg($"[{sceneName}] s_MAXPLAYERS {s_MAXPLAYERS} -> {Target}");
}
RaiseFusionPlayerSlots(sceneName);
}
catch (Exception ex)
{
((MelonBase)this).LoggerInstance.Warning("s_MAXPLAYERS patch failed: " + ex.Message);
}
}
}
[HarmonyPatch(typeof(CreateLobbySettings), "OnEnable")]
internal static class Patch_ExpandDropdown
{
private static void Postfix(CreateLobbySettings __instance)
{
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Expected O, but got Unknown
try
{
TMP_Dropdown maxPlayersDropdown = __instance.maxPlayersDropdown;
if (!((Object)(object)maxPlayersDropdown == (Object)null))
{
int count = maxPlayersDropdown.options.Count;
while (maxPlayersDropdown.options.Count < Mod.Target)
{
maxPlayersDropdown.options.Add(new OptionData((maxPlayersDropdown.options.Count + 1).ToString()));
}
if (maxPlayersDropdown.options.Count != count)
{
maxPlayersDropdown.RefreshShownValue();
Mod.Log($"maxPlayersDropdown expanded {count} -> {maxPlayersDropdown.options.Count}");
}
}
}
catch (Exception value)
{
Mod.Log($"ExpandDropdown error: {value}");
}
}
}
[HarmonyPatch(typeof(CreateLobbySettings), "ChangeMaxPlayers")]
internal static class Patch_ObserveChange
{
private static void Postfix(CreateLobbySettings __instance, int players)
{
Mod.Log($"ChangeMaxPlayers(arg={players}) -> field maxPlayers={__instance.maxPlayers}");
}
}
[HarmonyPatch(typeof(CreateLobbySettings), "StartLobby")]
internal static class Patch_StartLobby
{
private static void Prefix(CreateLobbySettings __instance)
{
Mod.SelectedMax = Math.Max(1, __instance.maxPlayers);
Mod.Log($"StartLobby: ui maxPlayers={__instance.maxPlayers} => SelectedMax={Mod.SelectedMax}");
Mod.RaiseFusionPlayerSlots("StartLobby");
}
private static void Postfix()
{
Mod.Log($"StartLobby done: PendingLobbySettings.maxPlayers={PendingLobbySettings.maxPlayers}");
if (Mod.SelectedMax > PendingLobbySettings.maxPlayers)
{
Mod.Log($"Pending maxPlayers clamped? {PendingLobbySettings.maxPlayers} -> {Mod.SelectedMax}");
PendingLobbySettings.maxPlayers = Mod.SelectedMax;
}
}
}
[HarmonyPatch(typeof(SteamMatchmaking), "CreateLobby")]
internal static class Patch_SteamCreateLobby
{
private static void Prefix(ELobbyType eLobbyType, ref int cMaxMembers)
{
//IL_0080: 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)
if (Mod.SelectedMax > cMaxMembers)
{
Mod.Log($"Steam CreateLobby({eLobbyType}): cMaxMembers {cMaxMembers} -> {Mod.SelectedMax}");
cMaxMembers = Mod.SelectedMax;
}
else
{
Mod.Log($"Steam CreateLobby({eLobbyType}): cMaxMembers={cMaxMembers} (no change)");
}
}
}
[HarmonyPatch(typeof(LoadBalancingClient), "OpCreateRoom")]
internal static class Patch_OpCreateRoom
{
private static void Prefix(EnterRoomParams enterRoomParams)
{
try
{
RoomOptions val = ((enterRoomParams != null) ? enterRoomParams.RoomOptions : null);
if (val != null)
{
Mod.Log($"OpCreateRoom: RoomOptions.MaxPlayers={val.MaxPlayers}, SelectedMax={Mod.SelectedMax}");
if (Mod.SelectedMax > 0 && val.MaxPlayers > 0 && val.MaxPlayers < Mod.SelectedMax)
{
val.MaxPlayers = Mod.SelectedMax;
Mod.Log($"OpCreateRoom: MaxPlayers -> {val.MaxPlayers}");
}
}
}
catch (Exception value)
{
Mod.Log($"OpCreateRoom error: {value}");
}
}
}
[HarmonyPatch(typeof(LoadBalancingClient), "OpJoinOrCreateRoom")]
internal static class Patch_OpJoinOrCreateRoom
{
private static void Prefix(EnterRoomParams enterRoomParams)
{
try
{
RoomOptions val = ((enterRoomParams != null) ? enterRoomParams.RoomOptions : null);
if (val != null)
{
Mod.Log($"OpJoinOrCreateRoom: RoomOptions.MaxPlayers={val.MaxPlayers}, SelectedMax={Mod.SelectedMax}");
if (Mod.SelectedMax > 0 && val.MaxPlayers > 0 && val.MaxPlayers < Mod.SelectedMax)
{
val.MaxPlayers = Mod.SelectedMax;
Mod.Log($"OpJoinOrCreateRoom: MaxPlayers -> {val.MaxPlayers}");
}
}
}
catch (Exception value)
{
Mod.Log($"OpJoinOrCreateRoom error: {value}");
}
}
}
[HarmonyPatch(typeof(LoadBalancingClient), "OpJoinRandomOrCreateRoom")]
internal static class Patch_OpJoinRandomOrCreateRoom
{
private static void Prefix(EnterRoomParams createRoomParams)
{
try
{
RoomOptions val = ((createRoomParams != null) ? createRoomParams.RoomOptions : null);
if (val != null)
{
Mod.Log($"OpJoinRandomOrCreateRoom: RoomOptions.MaxPlayers={val.MaxPlayers}, SelectedMax={Mod.SelectedMax}");
if (Mod.SelectedMax > 0 && val.MaxPlayers > 0 && val.MaxPlayers < Mod.SelectedMax)
{
val.MaxPlayers = Mod.SelectedMax;
Mod.Log($"OpJoinRandomOrCreateRoom: MaxPlayers -> {val.MaxPlayers}");
}
}
}
catch (Exception value)
{
Mod.Log($"OpJoinRandomOrCreateRoom error: {value}");
}
}
}
}