using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using FusionPlayerJoinLogger;
using LabFusion.Player;
using LabFusion.SDK.Metadata;
using LabFusion.Utilities;
using MelonLoader;
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: MelonInfo(typeof(Core), "FusionPlayerJoinLogger", "1.0.0", "FAIXI", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace FusionPlayerJoinLogger;
public class Core : MelonMod
{
private const string TAG = "[FPJL] ";
private const int SNAPSHOT_DELAY_FRAMES = 90;
private const int RETRY_DELAY_FRAMES = 90;
private static bool _hooked;
private static int _lastSnapshotCount;
public override void OnInitializeMelon()
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Expected O, but got Unknown
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Expected O, but got Unknown
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Expected O, but got Unknown
//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
try
{
MultiplayerHooking.OnPlayerJoined += new PlayerUpdate(HandlePlayerJoined);
MultiplayerHooking.OnPlayerLeft += new PlayerUpdate(HandlePlayerLeft);
MultiplayerHooking.OnJoinedServer += new ServerEvent(HandleJoinedServer);
MultiplayerHooking.OnStartedServer += new ServerEvent(HandleStartedServer);
MultiplayerHooking.OnDisconnected += new ServerEvent(HandleDisconnected);
_hooked = true;
((MelonBase)this).LoggerInstance.Msg("v1.0.0 ready — join hook + lobby snapshot armed.");
}
catch (global::System.Exception ex)
{
((MelonBase)this).LoggerInstance.Error(string.Concat((object)"init failed: ", (object)ex));
}
}
public override void OnDeinitializeMelon()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Expected O, but got Unknown
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Expected O, but got Unknown
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Expected O, but got Unknown
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Expected O, but got Unknown
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Expected O, but got Unknown
if (!_hooked)
{
return;
}
_hooked = false;
try
{
MultiplayerHooking.OnPlayerJoined -= new PlayerUpdate(HandlePlayerJoined);
}
catch (global::System.Exception)
{
}
try
{
MultiplayerHooking.OnPlayerLeft -= new PlayerUpdate(HandlePlayerLeft);
}
catch (global::System.Exception)
{
}
try
{
MultiplayerHooking.OnJoinedServer -= new ServerEvent(HandleJoinedServer);
}
catch (global::System.Exception)
{
}
try
{
MultiplayerHooking.OnStartedServer -= new ServerEvent(HandleStartedServer);
}
catch (global::System.Exception)
{
}
try
{
MultiplayerHooking.OnDisconnected -= new ServerEvent(HandleDisconnected);
}
catch (global::System.Exception)
{
}
}
private static void HandlePlayerJoined(PlayerID id)
{
try
{
if (id == null)
{
MelonLogger.Warning("[FPJL] WARNING: player joined with a null PlayerID, skipped.");
return;
}
bool flag = false;
try
{
flag = id.IsMe;
}
catch (global::System.Exception)
{
}
if (!flag)
{
MelonLogger.Msg("[FPJL] Player joined | " + Describe(id));
}
}
catch (global::System.Exception ex2)
{
MelonLogger.Warning("[FPJL] join handler failed: " + ex2.Message);
}
}
private static void HandlePlayerLeft(PlayerID id)
{
try
{
if (id != null)
{
bool flag = false;
try
{
flag = id.IsMe;
}
catch (global::System.Exception)
{
}
if (!flag)
{
MelonLogger.Msg("[FPJL] Player left | " + Describe(id));
}
}
}
catch (global::System.Exception ex2)
{
MelonLogger.Warning("[FPJL] leave handler failed: " + ex2.Message);
}
}
private static void HandleJoinedServer()
{
try
{
MelonCoroutines.Start(SnapshotRoutine());
}
catch (global::System.Exception ex)
{
MelonLogger.Warning("[FPJL] could not start snapshot routine: " + ex.Message);
}
}
private static void HandleStartedServer()
{
try
{
MelonCoroutines.Start(SnapshotRoutine());
}
catch (global::System.Exception ex)
{
MelonLogger.Warning("[FPJL] could not start snapshot routine: " + ex.Message);
}
}
private static void HandleDisconnected()
{
try
{
_lastSnapshotCount = 0;
}
catch (global::System.Exception)
{
}
}
private static global::System.Collections.IEnumerator SnapshotRoutine()
{
for (int i = 0; i < 90; i++)
{
yield return null;
}
SnapshotLobbyMembers();
if (_lastSnapshotCount == 0 && SafePlayerCount() > 1)
{
MelonLogger.Msg("[FPJL] no members found yet, retrying snapshot...");
for (int j = 0; j < 90; j++)
{
yield return null;
}
SnapshotLobbyMembers();
}
}
private static void SnapshotLobbyMembers()
{
//IL_014b: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
int num = 0;
MelonLogger.Msg("[FPJL] Lobby snapshot start | Local player: " + LocalNickname());
HashSet<byte> val = new HashSet<byte>();
try
{
int num2 = SafeMinId();
int num3 = SafeMaxId();
for (int i = num2; i <= num3; i++)
{
try
{
PlayerID playerID = PlayerIDManager.GetPlayerID((byte)i);
if (playerID != null)
{
byte b;
try
{
b = playerID.SmallID;
}
catch (global::System.Exception)
{
b = (byte)i;
}
if (val.Add(b) && !IsLocal(playerID) && ReportMember(playerID))
{
num++;
}
}
}
catch (global::System.Exception ex2)
{
MelonLogger.Warning(string.Concat(new object[4] { "[FPJL] scan error at session id ", i, ": ", ex2.Message }));
}
}
}
catch (global::System.Exception ex2)
{
MelonLogger.Warning("[FPJL] id scan failed: " + ex2.Message);
}
if (num == 0 && SafePlayerCount() > 1)
{
List<PlayerID> val2 = new List<PlayerID>();
try
{
Enumerator<PlayerID> enumerator = PlayerIDManager.PlayerIDs.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
PlayerID playerID = enumerator.Current;
if (playerID != null)
{
val2.Add(playerID);
}
}
}
finally
{
((global::System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
}
}
catch (global::System.Exception ex2)
{
MelonLogger.Warning("[FPJL] PlayerIDs enumeration failed: " + ex2.Message);
}
for (int i = 0; i < val2.Count; i++)
{
try
{
PlayerID playerID = val2[i];
byte b;
try
{
b = playerID.SmallID;
}
catch (global::System.Exception)
{
b = 0;
}
if (val.Add(b) && !IsLocal(playerID) && ReportMember(playerID))
{
num++;
}
}
catch (global::System.Exception ex2)
{
MelonLogger.Warning("[FPJL] member report failed: " + ex2.Message);
}
}
}
_lastSnapshotCount = num;
MelonLogger.Msg(string.Concat((object)"[FPJL] Lobby snapshot end | Total members: ", (object)num));
}
private static bool ReportMember(PlayerID p)
{
ulong num = 0uL;
bool flag = true;
try
{
num = p.PlatformID;
}
catch (global::System.Exception)
{
flag = false;
}
if (!flag || num == 0)
{
MelonLogger.Warning(string.Concat((object)"[FPJL] WARNING: PlayerID is null for session ID ", (object)SafeSmallId(p), (object)", PlatformID unavailable."));
return false;
}
MelonLogger.Msg(string.Concat(new object[4]
{
"[FPJL] Lobby member | Nickname: ",
Nickname(p),
" | PlatformID: ",
num
}));
return true;
}
private static string Describe(PlayerID p)
{
ulong num = 0uL;
try
{
num = p.PlatformID;
}
catch (global::System.Exception)
{
}
return string.Concat(new object[4]
{
"Nickname: ",
Nickname(p),
" | PlatformID: ",
num
});
}
private static string Nickname(PlayerID p)
{
try
{
PlayerMetadata metadata = p.Metadata;
if (metadata == null)
{
return "(no metadata)";
}
MetadataVariable nickname = metadata.Nickname;
if (nickname != null)
{
string valueOrEmpty = nickname.GetValueOrEmpty();
if (!string.IsNullOrEmpty(valueOrEmpty))
{
return valueOrEmpty;
}
}
MetadataVariable username = metadata.Username;
if (username != null)
{
string valueOrEmpty2 = username.GetValueOrEmpty();
if (!string.IsNullOrEmpty(valueOrEmpty2))
{
return valueOrEmpty2;
}
}
}
catch (global::System.Exception)
{
}
return "(unknown)";
}
private static string LocalNickname()
{
try
{
PlayerID localID = PlayerIDManager.LocalID;
if (localID == null)
{
return "(none)";
}
return Nickname(localID);
}
catch (global::System.Exception)
{
return "(unknown)";
}
}
private static bool IsLocal(PlayerID p)
{
try
{
return p.IsMe;
}
catch (global::System.Exception)
{
return false;
}
}
private static byte SafeSmallId(PlayerID p)
{
try
{
return p.SmallID;
}
catch (global::System.Exception)
{
return 0;
}
}
private static int SafePlayerCount()
{
try
{
return PlayerIDManager.PlayerCount;
}
catch (global::System.Exception)
{
return 0;
}
}
private static int SafeMinId()
{
try
{
return 0;
}
catch (global::System.Exception)
{
return 0;
}
}
private static int SafeMaxId()
{
try
{
return 255;
}
catch (global::System.Exception)
{
return 255;
}
}
}