Decompiled source of SpawnLogger v1.2.2

Mods/SpawnLogger.dll

Decompiled a day ago
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);
			}
		}
	}
}