using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BoneLib;
using BoneLib.BoneMenu;
using HarmonyLib;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Pool;
using Il2CppSLZ.Marrow.Warehouse;
using LabFusion.Network;
using LabFusion.Player;
using LabFusion.Utilities;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using SpawnLogger;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(/*Could not decode attribute arguments.*/)]
[assembly: MelonInfo(typeof(SpawnLoggerMod), "Spawn Logger", "1.1.0", "Local Utility", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : System.Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(/*Could not decode attribute arguments.*/)]
internal sealed class RefSafetyRulesAttribute : System.Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace SpawnLogger
{
public sealed class SpawnLoggerMod : MelonMod
{
private sealed class PlayerLog
{
public string DisplayName;
public readonly List<string> Entries = new List<string>();
public Page MenuPage;
}
private sealed class LogEntry
{
public ulong PlatformID;
public string Line;
}
[CompilerGenerated]
private static class <>O
{
public static PlayerUpdate <0>__OnPlayerJoined;
public static PlayerUpdate <1>__OnPlayerLeft;
public static UpdateEvent <2>__OnTargetLevelLoaded;
public static Action <3>__ClearAll;
}
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static Action<bool> <>9__17_0;
public static Action <>9__22_0;
public static Action <>9__22_1;
public static Action <>9__23_0;
public static Action <>9__23_1;
internal void <CreateMenu>b__17_0(bool value)
{
_autoClearOnLeave.Value = value;
MelonPreferences.Save();
}
internal void <RefreshPlayerPage>b__22_0()
{
}
internal void <RefreshPlayerPage>b__22_1()
{
}
internal void <RefreshAllLogPage>b__23_0()
{
}
internal void <RefreshAllLogPage>b__23_1()
{
}
}
private const int MaxLogEntries = 30;
private const float LoggingArmDelaySeconds = 5f;
private static readonly Dictionary<ulong, PlayerLog> _playerLogs = new Dictionary<ulong, PlayerLog>();
private static readonly List<LogEntry> _allEntries = new List<LogEntry>();
private static Page _allLogPage;
private static Page _playersPage;
private static bool _menuCreated;
private static bool _loggingArmed;
private static float _armTimer;
private static MelonPreferences_Category _prefs;
private static MelonPreferences_Entry<bool> _autoClearOnLeave;
public override void OnInitializeMelon()
{
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Expected O, but got Unknown
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Expected O, but got Unknown
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Expected O, but got Unknown
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Expected O, but got Unknown
_prefs = MelonPreferences.CreateCategory("SpawnLogger");
_autoClearOnLeave = _prefs.CreateEntry<bool>("AutoClearOnPlayerLeave", true, "Auto-Clear On Player Leave", "When a player disconnects, automatically clear their per-player log and remove their entries from the merged All Spawns log.", false, false, (ValueValidator)null, (string)null);
Hooking.OnUIRigCreated += new Action(CreateMenu);
object obj = <>O.<0>__OnPlayerJoined;
if (obj == null)
{
PlayerUpdate val = OnPlayerJoined;
<>O.<0>__OnPlayerJoined = val;
obj = (object)val;
}
MultiplayerHooking.OnPlayerJoined += (PlayerUpdate)obj;
object obj2 = <>O.<1>__OnPlayerLeft;
if (obj2 == null)
{
PlayerUpdate val2 = OnPlayerLeft;
<>O.<1>__OnPlayerLeft = val2;
obj2 = (object)val2;
}
MultiplayerHooking.OnPlayerLeft += (PlayerUpdate)obj2;
object obj3 = <>O.<2>__OnTargetLevelLoaded;
if (obj3 == null)
{
UpdateEvent val3 = OnTargetLevelLoaded;
<>O.<2>__OnTargetLevelLoaded = val3;
obj3 = (object)val3;
}
MultiplayerHooking.OnTargetLevelLoaded += (UpdateEvent)obj3;
}
public override void OnDeinitializeMelon()
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Expected O, but got Unknown
//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_002e: Expected O, but got Unknown
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Expected O, but got Unknown
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Expected O, but got Unknown
Hooking.OnUIRigCreated -= new Action(CreateMenu);
object obj = <>O.<0>__OnPlayerJoined;
if (obj == null)
{
PlayerUpdate val = OnPlayerJoined;
<>O.<0>__OnPlayerJoined = val;
obj = (object)val;
}
MultiplayerHooking.OnPlayerJoined -= (PlayerUpdate)obj;
object obj2 = <>O.<1>__OnPlayerLeft;
if (obj2 == null)
{
PlayerUpdate val2 = OnPlayerLeft;
<>O.<1>__OnPlayerLeft = val2;
obj2 = (object)val2;
}
MultiplayerHooking.OnPlayerLeft -= (PlayerUpdate)obj2;
object obj3 = <>O.<2>__OnTargetLevelLoaded;
if (obj3 == null)
{
UpdateEvent val3 = OnTargetLevelLoaded;
<>O.<2>__OnTargetLevelLoaded = val3;
obj3 = (object)val3;
}
MultiplayerHooking.OnTargetLevelLoaded -= (UpdateEvent)obj3;
}
public override void OnUpdate()
{
if (!_loggingArmed && !(_armTimer <= 0f))
{
_armTimer -= Time.deltaTime;
if (_armTimer <= 0f)
{
_loggingArmed = true;
}
}
}
private static void OnTargetLevelLoaded()
{
_loggingArmed = false;
_armTimer = 5f;
}
private void CreateMenu()
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: 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_0041: 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_004c: Expected O, but got Unknown
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
if (_menuCreated)
{
return;
}
Page val = Page.Root.CreatePage("Spawn Logger", Color.yellow, 0, true);
Color red = Color.red;
object obj = <>O.<3>__ClearAll;
if (obj == null)
{
Action val2 = ClearAll;
<>O.<3>__ClearAll = val2;
obj = (object)val2;
}
val.CreateFunction("Clear All Logs", red, (Action)obj);
val.CreateBool("Auto-Clear On Leave", Color.yellow, _autoClearOnLeave.Value, (Action<bool>)delegate(bool value)
{
_autoClearOnLeave.Value = value;
MelonPreferences.Save();
});
_allLogPage = val.CreatePage("All Spawns", Color.yellow, 0, true);
_playersPage = val.CreatePage("Players", Color.yellow, 0, true);
_menuCreated = true;
Enumerator<PlayerID> enumerator = PlayerIDManager.PlayerIDs.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
PlayerID current = enumerator.Current;
GetOrCreatePlayerLog(current);
}
}
finally
{
((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
}
RefreshAllLogPage();
}
private static void OnPlayerJoined(PlayerID id)
{
GetOrCreatePlayerLog(id);
}
private static void OnPlayerLeft(PlayerID id)
{
PlayerLog playerLog = default(PlayerLog);
if (id == null || !_autoClearOnLeave.Value || !_playerLogs.TryGetValue(id.PlatformID, ref playerLog))
{
return;
}
_playerLogs.Remove(id.PlatformID);
if (playerLog.MenuPage != null)
{
Page playersPage = _playersPage;
if (playersPage != null)
{
playersPage.RemovePage(playerLog.MenuPage);
}
}
_allEntries.RemoveAll((Predicate<LogEntry>)((LogEntry entry) => entry.PlatformID == id.PlatformID));
RefreshAllLogPage();
}
private static void ClearAll()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
_allEntries.Clear();
RefreshAllLogPage();
Enumerator<ulong, PlayerLog> enumerator = _playerLogs.Values.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
PlayerLog current = enumerator.Current;
current.Entries.Clear();
RefreshPlayerPage(current);
}
}
finally
{
((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
}
}
private static PlayerLog GetOrCreatePlayerLog(PlayerID id)
{
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
if (id == null)
{
return null;
}
string text2 = default(string);
string text = (MetadataHelper.TryGetDisplayName(id, ref text2) ? text2 : $"Player {id.SmallID}");
PlayerLog playerLog = default(PlayerLog);
if (!_playerLogs.TryGetValue(id.PlatformID, ref playerLog))
{
playerLog = new PlayerLog
{
DisplayName = text
};
_playerLogs[id.PlatformID] = playerLog;
}
else if (playerLog.DisplayName != text)
{
playerLog.DisplayName = text;
if (playerLog.MenuPage != null)
{
playerLog.MenuPage.Name = text;
}
}
if (playerLog.MenuPage == null && _playersPage != null)
{
playerLog.MenuPage = _playersPage.CreatePage(text, Color.white, 0, true);
RefreshPlayerPage(playerLog);
}
return playerLog;
}
private static void RefreshPlayerPage(PlayerLog log)
{
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Expected O, but got Unknown
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Expected O, but got Unknown
if (log?.MenuPage == null)
{
return;
}
log.MenuPage.RemoveAll();
if (log.Entries.Count == 0)
{
Page menuPage = log.MenuPage;
Color gray = Color.gray;
object obj = <>c.<>9__22_0;
if (obj == null)
{
Action val = delegate
{
};
<>c.<>9__22_0 = val;
obj = (object)val;
}
menuPage.CreateFunction("No spawns logged yet", gray, (Action)obj);
return;
}
Enumerator<string> enumerator = log.Entries.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
string current = enumerator.Current;
Page menuPage2 = log.MenuPage;
Color white = Color.white;
object obj2 = <>c.<>9__22_1;
if (obj2 == null)
{
Action val2 = delegate
{
};
<>c.<>9__22_1 = val2;
obj2 = (object)val2;
}
menuPage2.CreateFunction(current, white, (Action)obj2);
}
}
finally
{
((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
}
}
private static void RefreshAllLogPage()
{
//IL_006b: 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_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Expected O, but got Unknown
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Expected O, but got Unknown
if (_allLogPage == null)
{
return;
}
_allLogPage.RemoveAll();
if (_allEntries.Count == 0)
{
Page allLogPage = _allLogPage;
Color gray = Color.gray;
object obj = <>c.<>9__23_0;
if (obj == null)
{
Action val = delegate
{
};
<>c.<>9__23_0 = val;
obj = (object)val;
}
allLogPage.CreateFunction("No spawns logged yet", gray, (Action)obj);
return;
}
Enumerator<LogEntry> enumerator = _allEntries.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
LogEntry current = enumerator.Current;
Page allLogPage2 = _allLogPage;
string line = current.Line;
Color white = Color.white;
object obj2 = <>c.<>9__23_1;
if (obj2 == null)
{
Action val2 = delegate
{
};
<>c.<>9__23_1 = val2;
obj2 = (object)val2;
}
allLogPage2.CreateFunction(line, white, (Action)obj2);
}
}
finally
{
((System.IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
}
}
private static string ResolveItemName(string barcode)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Expected O, but got Unknown
AssetWarehouse instance = AssetWarehouse.Instance;
Crate val = default(Crate);
if (instance != null && instance.TryGetCrate(new Barcode(barcode), ref val) && (Object)(object)val != (Object)null)
{
string title = ((Scannable)val).Title;
if (!string.IsNullOrWhiteSpace(title))
{
return title;
}
}
return barcode;
}
internal static void LogSpawn(byte ownerId, string barcode)
{
if (!_loggingArmed || string.IsNullOrEmpty(barcode) || barcode.StartsWith("SLZ.", (StringComparison)5))
{
return;
}
PlayerID playerID = PlayerIDManager.GetPlayerID(ownerId);
PlayerLog orCreatePlayerLog = GetOrCreatePlayerLog(playerID);
string text = orCreatePlayerLog?.DisplayName ?? $"Unknown (ID {ownerId})";
string text2 = ResolveItemName(barcode);
string text3 = $"[{System.DateTime.Now:HH:mm:ss}] {text}: {text2}";
_allEntries.Insert(0, new LogEntry
{
PlatformID = ((playerID != null) ? playerID.PlatformID : 0),
Line = text3
});
if (_allEntries.Count > 30)
{
_allEntries.RemoveAt(_allEntries.Count - 1);
}
RefreshAllLogPage();
if (orCreatePlayerLog != null)
{
orCreatePlayerLog.Entries.Insert(0, text3);
if (orCreatePlayerLog.Entries.Count > 30)
{
orCreatePlayerLog.Entries.RemoveAt(orCreatePlayerLog.Entries.Count - 1);
}
RefreshPlayerPage(orCreatePlayerLog);
}
MelonLogger.Msg(text3);
}
}
[HarmonyPatch(typeof(SpawnResponseMessage), "OnSpawnFinished")]
internal static class SpawnResponseMessage_OnSpawnFinished_Patch
{
private static void Postfix(SpawnResponseData data, Poolee poolee)
{
if (!((Object)(object)poolee != (Object)null) || !((Object)(object)((Component)poolee).gameObject.GetComponentInChildren<Magazine>() != (Object)null))
{
SpawnLoggerMod.LogSpawn(data.OwnerID, data.SpawnData.Barcode);
}
}
}
}