Decompiled source of StreamOverlays v1.4.3

com.github.zehsteam.StreamOverlays.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalConfig;
using LethalConfig.ConfigItems;
using LethalConfig.ConfigItems.Options;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using ShipInventory.Items;
using ShipInventory.Objects;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using WebSocketSharp.Net;
using WebSocketSharp.Server;
using com.github.zehsteam.StreamOverlays.Dependencies;
using com.github.zehsteam.StreamOverlays.Dependencies.ShipInventoryProxy;
using com.github.zehsteam.StreamOverlays.Dependencies.ShipInventoryProxy.Patches;
using com.github.zehsteam.StreamOverlays.Dependencies.Vanilla;
using com.github.zehsteam.StreamOverlays.Helpers;
using com.github.zehsteam.StreamOverlays.Patches;
using com.github.zehsteam.StreamOverlays.Server;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.zehsteam.StreamOverlays")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Display real-time game stats on your stream using browser sources. Shows the player count, current moon, weather, day count, quota, and ship loot. Works with OBS, Streamlabs OBS, and similar software for Twitch, YouTube, TikTok, Kick, and more.")]
[assembly: AssemblyFileVersion("1.4.3.0")]
[assembly: AssemblyInformationalVersion("1.4.3+3ee8d9da5e79ce1f8fef21824467f528a433970f")]
[assembly: AssemblyProduct("StreamOverlays")]
[assembly: AssemblyTitle("com.github.zehsteam.StreamOverlays")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.3.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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace com.github.zehsteam.StreamOverlays
{
	internal class ConfigManager
	{
		public ConfigEntry<bool> ExtendedLogging { get; private set; }

		public ConfigEntry<string> CrewStat_Label { get; private set; }

		public ConfigEntry<string> MoonStat_Label { get; private set; }

		public ConfigEntry<bool> MoonStat_ShowWeatherIcon { get; private set; }

		public ConfigEntry<string> DayStat_Label { get; private set; }

		public ConfigEntry<string> QuotaStat_Label { get; private set; }

		public ConfigEntry<string> LootStat_Label { get; private set; }

		public ConfigEntry<bool> LootStat_OnlyUpdateEndOfDay { get; private set; }

		public ConfigEntry<string> AveragePerDayStat_Label { get; private set; }

		public ConfigEntry<bool> Server_AutoStart { get; private set; }

		public ConfigEntry<int> Server_HttpPort { get; private set; }

		public ConfigEntry<int> Server_WebSocketPort { get; private set; }

		public ConfigManager()
		{
			BindConfigs();
			ConfigHelper.ClearUnusedEntries();
		}

		private void BindConfigs()
		{
			ConfigHelper.SkipAutoGen();
			ExtendedLogging = ConfigHelper.Bind("General", "ExtendedLogging", defaultValue: false, requiresRestart: false, "Enable extended logging.");
			CrewStat_Label = ConfigHelper.Bind("Crew Stat", "Label", "Crew: {value}", requiresRestart: false, "The formatting of the Crew stat display text. {value} is the amount of players in the current lobby.");
			CrewStat_Label.SettingChanged += delegate
			{
				WebServer.UpdateOverlaysFormatting();
			};
			MoonStat_Label = ConfigHelper.Bind("Moon Stat", "Label", "Moon: {value}", requiresRestart: false, "The formatting of the Moon stat display text. {value} is the name of the current moon.");
			MoonStat_ShowWeatherIcon = ConfigHelper.Bind("Moon Stat", "ShowWeatherIcon", defaultValue: true, requiresRestart: false, "If enabled, will show an icon for the current weather after the moon name.");
			MoonStat_Label.SettingChanged += delegate
			{
				WebServer.UpdateOverlaysFormatting();
			};
			MoonStat_ShowWeatherIcon.SettingChanged += delegate
			{
				WebServer.UpdateOverlaysData();
			};
			DayStat_Label = ConfigHelper.Bind("Day Stat", "Label", "Day: {value} ({value2}/{value3})", requiresRestart: false, "The formatting of the Day stat display text. {value} is the day number. {value2} is the day number in the current quota. {value3} is the amount of days in a quota. You can remove {value2} and {value3} if you want to.");
			DayStat_Label.SettingChanged += delegate
			{
				WebServer.UpdateOverlaysFormatting();
			};
			QuotaStat_Label = ConfigHelper.Bind("Quota Stat", "Label", "Quota {value2}: ${value}", requiresRestart: false, "The formatting of the Quota stat display text. {value} is the current profit quota. {value2} is the quota number/index. You can remove {value2} if you want to.");
			QuotaStat_Label.SettingChanged += delegate
			{
				WebServer.UpdateOverlaysFormatting();
			};
			LootStat_Label = ConfigHelper.Bind("Loot Stat", "Label", "Ship Loot: ${value}", requiresRestart: false, "The formatting of the Loot stat display text. {value} is the total scrap value on the ship and attached company cruiser.");
			LootStat_OnlyUpdateEndOfDay = ConfigHelper.Bind("Loot Stat", "OnlyUpdateEndOfDay", defaultValue: true, requiresRestart: false, "If enabled, the Loot stat will only update when the day ends or if you are in orbit.");
			LootStat_Label.SettingChanged += delegate
			{
				WebServer.UpdateOverlaysFormatting();
			};
			AveragePerDayStat_Label = ConfigHelper.Bind("Average Per Day Stat", "Label", "Avg/Day: ${value}", requiresRestart: false, "The formatting of the Average Per Day stat display text. {value} is the average collected scrap per day.");
			AveragePerDayStat_Label.SettingChanged += delegate
			{
				WebServer.UpdateOverlaysFormatting();
			};
			Server_AutoStart = ConfigHelper.Bind("Server", "AutoStart", defaultValue: true, requiresRestart: false, "If enabled, the server will automatically start when you launch the game.");
			ConfigHelper.AddButton("Server", "Start Server", "Start the server.", "Start", WebServer.Start);
			ConfigHelper.AddButton("Server", "Stop Server", "Stop the server.", "Stop", WebServer.Stop);
			Server_HttpPort = ConfigHelper.Bind("Server", "HttpPort", 8080, requiresRestart: false, "The HTTP port for the server.");
			Server_WebSocketPort = ConfigHelper.Bind("Server", "WebSocketPort", 8000, requiresRestart: false, "The WebSocket port for the server.");
		}
	}
	internal static class DayManager
	{
		public static List<DayData> DayDataList = new List<DayData>();

		public static void LoadDayData()
		{
			DayDataList = new List<DayData>();
			if (!NetworkUtils.IsServer || !SaveSystem.KeyExists("DayData"))
			{
				return;
			}
			try
			{
				string text = SaveSystem.LoadData<string>("DayData");
				DayDataList = JsonConvert.DeserializeObject<List<DayData>>(text);
				Plugin.Instance.LogInfoExtended("Loaded day data from save file. " + text);
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to load day data from save file. {arg}");
			}
		}

		public static void SaveDayData()
		{
			if (!NetworkUtils.IsServer)
			{
				return;
			}
			try
			{
				string text = JsonConvert.SerializeObject((object)DayDataList);
				SaveSystem.SaveData("DayData", text);
				Plugin.Instance.LogInfoExtended("Saved day data to save file. " + text);
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to save day data to save file. {arg}");
			}
		}

		public static void AddDayData(int scrapCollected)
		{
			if (CanAddDayData())
			{
				int dayNumber = GetDayNumber();
				if (!DayDataList.Any((DayData x) => x.Day == dayNumber))
				{
					DayDataList.Add(new DayData(dayNumber, scrapCollected));
				}
			}
		}

		private static bool CanAddDayData()
		{
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.currentLevel == (Object)null)
			{
				return false;
			}
			return StartOfRound.Instance.currentLevel.spawnEnemiesAndScrap;
		}

		public static void ResetSavedDayData()
		{
			DayDataList = new List<DayData>();
			SaveDayData();
		}

		public static int GetDayNumber()
		{
			return DayDataList.Count + 1;
		}

		public static int GetAveragePerDay()
		{
			if (DayDataList.Count == 0)
			{
				return 0;
			}
			return DayDataList.Sum((DayData x) => x.ScrapCollected) / DayDataList.Count;
		}
	}
	[Serializable]
	public struct DayData
	{
		public int Day;

		public int ScrapCollected;

		public DayData(int day, int scrapCollected)
		{
			Day = day;
			ScrapCollected = scrapCollected;
		}
	}
	internal static class LootManager
	{
		private static int _shipLootTotal;

		private static int _vehicleLootTotal;

		private static int _shipInventoryLootTotal;

		public static bool CanUpdateLootTotal()
		{
			if (!Plugin.ConfigManager.LootStat_OnlyUpdateEndOfDay.Value)
			{
				return true;
			}
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.currentLevel == (Object)null)
			{
				return false;
			}
			if (!StartOfRound.Instance.currentLevel.spawnEnemiesAndScrap)
			{
				return true;
			}
			return StartOfRound.Instance.inShipPhase;
		}

		public static void UpdateLootTotal()
		{
			_shipLootTotal = GetShipLootTotal();
			if (VehicleControllerProxy.Enabled)
			{
				_vehicleLootTotal = VehicleControllerProxy.GetLootTotal();
			}
			if (ShipInventoryProxy.Enabled)
			{
				_shipInventoryLootTotal = ShipInventoryProxy.GetLootTotal();
			}
		}

		public static int GetLootTotal()
		{
			return _shipLootTotal + _vehicleLootTotal + _shipInventoryLootTotal;
		}

		private static int GetShipLootTotal()
		{
			Transform hangarShipTransform = Utils.GetHangarShipTransform();
			if ((Object)(object)hangarShipTransform == (Object)null)
			{
				return 0;
			}
			List<GrabbableObject> list = ((Component)hangarShipTransform).GetComponentsInChildren<GrabbableObject>().ToList();
			list.AddRange(GetGrabbableObjectsFromShipPlaceableObjects());
			return list.Where(Utils.IsValidScrapAndNotHeld).Sum((GrabbableObject x) => x.scrapValue);
		}

		private static List<GrabbableObject> GetGrabbableObjectsFromShipPlaceableObjects()
		{
			List<GrabbableObject> list = new List<GrabbableObject>();
			AutoParentToShip[] array = Object.FindObjectsByType<AutoParentToShip>((FindObjectsSortMode)0);
			foreach (AutoParentToShip val in array)
			{
				if (!((Object)(object)((Component)val).transform.parent != (Object)null))
				{
					list.AddRange(((Component)val).GetComponentsInChildren<GrabbableObject>());
				}
			}
			return list;
		}
	}
	internal static class NetworkUtils
	{
		public static bool IsConnected
		{
			get
			{
				if ((Object)(object)NetworkManager.Singleton == (Object)null)
				{
					return false;
				}
				return NetworkManager.Singleton.IsConnectedClient;
			}
		}

		public static bool IsServer
		{
			get
			{
				if ((Object)(object)NetworkManager.Singleton == (Object)null)
				{
					return false;
				}
				return NetworkManager.Singleton.IsServer;
			}
		}

		public static bool IsHost
		{
			get
			{
				if ((Object)(object)NetworkManager.Singleton == (Object)null)
				{
					return false;
				}
				return NetworkManager.Singleton.IsHost;
			}
		}

		public static ulong GetLocalClientId()
		{
			if ((Object)(object)NetworkManager.Singleton == (Object)null)
			{
				return 0uL;
			}
			return NetworkManager.Singleton.LocalClientId;
		}

		public static bool IsLocalClientId(ulong clientId)
		{
			return clientId == GetLocalClientId();
		}
	}
	internal static class PlayerUtils
	{
		public static PlayerControllerB GetLocalPlayerScript()
		{
			if ((Object)(object)GameNetworkManager.Instance == (Object)null)
			{
				return null;
			}
			return GameNetworkManager.Instance.localPlayerController;
		}

		public static bool IsLocalPlayer(PlayerControllerB playerScript)
		{
			return (Object)(object)playerScript == (Object)(object)GetLocalPlayerScript();
		}

		public static bool IsLocalPlayerSpawned()
		{
			return (Object)(object)GetLocalPlayerScript() != (Object)null;
		}

		public static PlayerControllerB GetPlayerScriptByClientId(ulong clientId)
		{
			if ((Object)(object)StartOfRound.Instance == (Object)null)
			{
				return null;
			}
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (val.actualClientId == clientId)
				{
					return val;
				}
			}
			return null;
		}
	}
	[BepInPlugin("com.github.zehsteam.StreamOverlays", "StreamOverlays", "1.4.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal class Plugin : BaseUnityPlugin
	{
		private readonly Harmony _harmony = new Harmony("com.github.zehsteam.StreamOverlays");

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Logger { get; private set; }

		internal static ConfigFile Config { get; private set; }

		internal static ConfigManager ConfigManager { get; private set; }

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			Logger = Logger.CreateLogSource("com.github.zehsteam.StreamOverlays");
			Logger.LogInfo((object)"StreamOverlays has awoken!");
			Config = Utils.CreateGlobalConfigFile();
			_harmony.PatchAll(typeof(NetworkManagerPatch));
			_harmony.PatchAll(typeof(GameNetworkManagerPatch));
			_harmony.PatchAll(typeof(StartOfRoundPatch));
			_harmony.PatchAll(typeof(RoundManagerPatch));
			_harmony.PatchAll(typeof(TimeOfDayPatch));
			_harmony.PatchAll(typeof(PlayerControllerBPatch));
			_harmony.PatchAll(typeof(DepositItemsDeskPatch));
			if (VehicleControllerProxy.Enabled)
			{
				VehicleControllerProxy.PatchAll(_harmony);
			}
			if (ShipInventoryProxy.Enabled)
			{
				ShipInventoryProxy.PatchAll(_harmony);
			}
			ConfigManager = new ConfigManager();
			Task.Run((Func<Task?>)WebServer.Initialize);
		}

		public void LogInfoExtended(object data)
		{
			LogExtended((LogLevel)16, data);
		}

		public void LogExtended(LogLevel level, object data)
		{
			//IL_0022: 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)
			if (ConfigManager == null || ConfigManager.ExtendedLogging == null)
			{
				Logger.Log(level, data);
			}
			else if (ConfigManager.ExtendedLogging.Value)
			{
				Logger.Log(level, data);
			}
		}
	}
	internal static class PluginNetworkManager
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__HandleCustomMessage;
		}

		public static void Initialize()
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			if ((Object)(object)NetworkManager.Singleton == (Object)null)
			{
				Plugin.Logger.LogError((object)"Failed to initialize PluginNetworkManager. NetworkManager.Singleton is null.");
				return;
			}
			if (NetworkManager.Singleton.CustomMessagingManager == null)
			{
				Plugin.Logger.LogError((object)"Failed to initialize PluginNetworkManager. NetworkManager.Singleton.CustomMessagingManager is null.");
				return;
			}
			CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager;
			object obj = <>O.<0>__HandleCustomMessage;
			if (obj == null)
			{
				HandleNamedMessageDelegate val = HandleCustomMessage;
				<>O.<0>__HandleCustomMessage = val;
				obj = (object)val;
			}
			customMessagingManager.RegisterNamedMessageHandler("ReceiveCustomMessage", (HandleNamedMessageDelegate)obj);
			Plugin.Logger.LogInfo((object)"PluginNetworkManager initialized successfully.");
		}

		public static void OnClientConnected(ulong clientId)
		{
			if (!NetworkUtils.IsServer)
			{
				return;
			}
			try
			{
				CustomMessage customMessage = new CustomMessage
				{
					DaysSpent = StartOfRound.Instance.gameStats.daysSpent,
					TimesFulfilledQuota = TimeOfDay.Instance.timesFulfilledQuota,
					DayDataList = DayManager.DayDataList.ToArray()
				};
				SendCustomMessageToClient(clientId, customMessage);
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to send CustomMessage data to client: {clientId}. {arg}");
			}
		}

		private static void SendCustomMessageToClient(ulong clientId, CustomMessage customMessage)
		{
			//IL_003d: 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_0054: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkUtils.IsServer)
			{
				Plugin.Logger.LogWarning((object)"Only the host can send messages to clients.");
				return;
			}
			try
			{
				FastBufferWriter val = default(FastBufferWriter);
				((FastBufferWriter)(ref val))..ctor(1024, (Allocator)2, -1);
				try
				{
					((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref customMessage.DaysSpent, default(ForPrimitives));
					((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref customMessage.TimesFulfilledQuota, default(ForPrimitives));
					int num = customMessage.DayDataList.Length;
					((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref num, default(ForPrimitives));
					DayData[] dayDataList = customMessage.DayDataList;
					for (int i = 0; i < dayDataList.Length; i++)
					{
						DayData dayData = dayDataList[i];
						((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref dayData.Day, default(ForPrimitives));
						((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref dayData.ScrapCollected, default(ForPrimitives));
					}
					NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("ReceiveCustomMessage", clientId, val, (NetworkDelivery)3);
					Plugin.Logger.LogInfo((object)$"Sent CustomMessage data to client: {clientId}");
				}
				finally
				{
					((IDisposable)(FastBufferWriter)(ref val)).Dispose();
				}
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to send CustomMessage data to client: {clientId}. {arg}");
			}
		}

		private static void HandleCustomMessage(ulong senderId, FastBufferReader reader)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			if (!((FastBufferReader)(ref reader)).TryBeginRead(8))
			{
				Plugin.Logger.LogWarning((object)"Failed to deserialize message: Insufficient data.");
				return;
			}
			try
			{
				CustomMessage customMessage = new CustomMessage();
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref customMessage.DaysSpent, default(ForPrimitives));
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref customMessage.TimesFulfilledQuota, default(ForPrimitives));
				int num = default(int);
				((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives));
				customMessage.DayDataList = new DayData[num];
				for (int i = 0; i < num; i++)
				{
					customMessage.DayDataList[i] = default(DayData);
					((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref customMessage.DayDataList[i].Day, default(ForPrimitives));
					((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref customMessage.DayDataList[i].ScrapCollected, default(ForPrimitives));
				}
				Plugin.Logger.LogInfo((object)$"Received message from client: {senderId}");
				ApplyCustomMessageData(customMessage);
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to deserialize message. {arg}");
			}
		}

		private static void ApplyCustomMessageData(CustomMessage customMessage)
		{
			if (customMessage == null)
			{
				Plugin.Logger.LogError((object)"Failed to apply CustomMessage data. CustomMessage is null.");
				return;
			}
			try
			{
				StartOfRound.Instance.gameStats.daysSpent = customMessage.DaysSpent;
				TimeOfDay.Instance.timesFulfilledQuota = customMessage.TimesFulfilledQuota;
				DayManager.DayDataList = customMessage.DayDataList.ToList();
				Plugin.Logger.LogInfo((object)"Applied CustomMessage data successfully!");
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to apply CustomMessage data. {arg}");
			}
		}
	}
	[Serializable]
	public class CustomMessage
	{
		public int DaysSpent;

		public int TimesFulfilledQuota;

		public DayData[] DayDataList;
	}
	internal static class SaveSystem
	{
		public static bool KeyExists(string key)
		{
			return ES3.KeyExists(GetBaseKey() + "." + key, GetCurrentSaveFilePath());
		}

		public static void SaveData<T>(string key, T data)
		{
			ES3.Save<T>(GetBaseKey() + "." + key, data, GetCurrentSaveFilePath());
		}

		public static T LoadData<T>(string key, T defaultValue = default(T))
		{
			return ES3.Load<T>(GetBaseKey() + "." + key, GetCurrentSaveFilePath(), defaultValue);
		}

		private static string GetBaseKey()
		{
			return MethodBase.GetCurrentMethod().DeclaringType.Namespace;
		}

		private static string GetCurrentSaveFilePath()
		{
			return GameNetworkManager.Instance.currentSaveFileName;
		}
	}
	internal static class Utils
	{
		public static string GetEnumName<T>(T e) where T : Enum
		{
			return Enum.GetName(typeof(T), e) ?? string.Empty;
		}

		public static string GetPluginDirectoryPath()
		{
			return Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location);
		}

		public static ConfigFile CreateConfigFile(string path, string name = null, bool saveOnInit = false)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			BepInPlugin metadata = MetadataHelper.GetMetadata((object)Plugin.Instance);
			if (name == null)
			{
				name = metadata.GUID;
			}
			name += ".cfg";
			return new ConfigFile(Path.Combine(path, name), saveOnInit, metadata);
		}

		public static ConfigFile CreateLocalConfigFile(string name = null, bool saveOnInit = false)
		{
			BepInPlugin metadata = MetadataHelper.GetMetadata((object)Plugin.Instance);
			if (name == null)
			{
				name = metadata.GUID + "-" + name;
			}
			return CreateConfigFile(Paths.ConfigPath, name, saveOnInit);
		}

		public static ConfigFile CreateGlobalConfigFile(string name = null, bool saveOnInit = false)
		{
			BepInPlugin metadata = MetadataHelper.GetMetadata((object)Plugin.Instance);
			string path = Path.Combine(Application.persistentDataPath, metadata.Name);
			if (name == null)
			{
				name = "global";
			}
			return CreateConfigFile(path, name, saveOnInit);
		}

		public static Coroutine StartCoroutine(IEnumerator routine)
		{
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				return ((MonoBehaviour)Plugin.Instance).StartCoroutine(routine);
			}
			if ((Object)(object)GameNetworkManager.Instance != (Object)null)
			{
				return ((MonoBehaviour)GameNetworkManager.Instance).StartCoroutine(routine);
			}
			Plugin.Logger.LogError((object)("Failed to start coroutine. " + routine));
			return null;
		}

		public static Transform GetHangarShipTransform()
		{
			if ((Object)(object)StartOfRound.Instance == (Object)null)
			{
				return null;
			}
			return StartOfRound.Instance.elevatorTransform;
		}

		public static bool CanShowOverlay()
		{
			if ((Object)(object)GameNetworkManager.Instance == (Object)null)
			{
				return false;
			}
			if (GameNetworkManager.Instance.isDisconnecting)
			{
				return false;
			}
			if (!PlayerUtils.IsLocalPlayerSpawned())
			{
				return false;
			}
			return true;
		}

		public static int GetPlayerCount()
		{
			if (NetworkUtils.IsServer)
			{
				if ((Object)(object)GameNetworkManager.Instance == (Object)null)
				{
					return 1;
				}
				return GameNetworkManager.Instance.connectedPlayers;
			}
			if ((Object)(object)StartOfRound.Instance == (Object)null)
			{
				return 1;
			}
			return StartOfRound.Instance.connectedPlayersAmount + 1;
		}

		public static string GetCurrentPlanetName()
		{
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.currentLevel == (Object)null)
			{
				return string.Empty;
			}
			return StartOfRound.Instance.currentLevel.PlanetName;
		}

		public static LevelWeatherType GetCurrentPlanetWeather()
		{
			//IL_0034: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.currentLevel == (Object)null)
			{
				return (LevelWeatherType)(-1);
			}
			return StartOfRound.Instance.currentLevel.currentWeather;
		}

		public static int GetDayInQuota()
		{
			if ((Object)(object)TimeOfDay.Instance == (Object)null)
			{
				return 1;
			}
			int num = Mathf.Max(TimeOfDay.Instance.daysUntilDeadline, 0);
			int num2 = 3;
			return num2 - num + 1;
		}

		public static int GetProfitQuota()
		{
			if ((Object)(object)TimeOfDay.Instance == (Object)null)
			{
				return 0;
			}
			return TimeOfDay.Instance.profitQuota;
		}

		public static int GetQuotaIndex()
		{
			if ((Object)(object)TimeOfDay.Instance == (Object)null)
			{
				return 1;
			}
			return TimeOfDay.Instance.timesFulfilledQuota + 1;
		}

		public static bool IsValidScrapAndNotHeld(GrabbableObject grabbableObject)
		{
			if (!IsValidScrap(grabbableObject))
			{
				return false;
			}
			if (grabbableObject.isHeld)
			{
				return false;
			}
			return true;
		}

		public static bool IsValidScrap(GrabbableObject grabbableObject)
		{
			if ((Object)(object)grabbableObject == (Object)null || (Object)(object)grabbableObject.itemProperties == (Object)null)
			{
				return false;
			}
			if (GrabbableObjectHelper.IsDeactivated(grabbableObject) || grabbableObject.itemUsedUp)
			{
				return false;
			}
			return grabbableObject.itemProperties.isScrap;
		}

		public static int GetScrapValueCollectedThisRound()
		{
			if ((Object)(object)StartOfRound.Instance == (Object)null)
			{
				return 0;
			}
			int num = 0;
			GrabbableObject[] array = Object.FindObjectsByType<GrabbableObject>((FindObjectsSortMode)0);
			foreach (GrabbableObject val in array)
			{
				if (IsValidScrap(val) && !val.scrapPersistedThroughRounds && !val.itemProperties.itemName.Equals("Body", StringComparison.OrdinalIgnoreCase) && (val.isInShipRoom || val.isInElevator))
				{
					num += val.scrapValue;
				}
			}
			if (ShipInventoryProxy.Enabled)
			{
				num += ShipInventoryProxy.GetLootTotal(onlyFromRound: true);
			}
			return num;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "com.github.zehsteam.StreamOverlays";

		public const string PLUGIN_NAME = "StreamOverlays";

		public const string PLUGIN_VERSION = "1.4.3";
	}
}
namespace com.github.zehsteam.StreamOverlays.Server
{
	public class OverlayBehavior : WebSocketBehavior
	{
		protected override void OnOpen()
		{
			UpdateOverlayFormatting();
			UpdateOverlayData();
		}

		public void SendJsonToClient(object jsonData)
		{
			((WebSocketBehavior)this).Send(JsonConvert.SerializeObject(jsonData));
		}

		public void UpdateOverlayFormatting()
		{
			SendJsonToClient(WebServer.GetOverlaysFormatting());
		}

		public void UpdateOverlayData()
		{
			SendJsonToClient(WebServer.GetOverlaysData());
		}
	}
	internal static class WebServer
	{
		private static HttpListener _httpListener;

		private static WebSocketServer _webSocketServer;

		private static readonly object _broadcastLock = new object();

		private static bool _isApplicationQuitting;

		public static int HttpPort => Plugin.ConfigManager.Server_HttpPort.Value;

		public static int WebSocketPort => Plugin.ConfigManager.Server_WebSocketPort.Value;

		public static bool IsRunning { get; private set; }

		public static async Task Initialize()
		{
			Application.quitting += delegate
			{
				_isApplicationQuitting = true;
				Stop();
			};
			if (WebsiteArchiveExists())
			{
				await DecompressWebsiteArchive();
			}
			if (!WebsiteFolderExists())
			{
				Plugin.Logger.LogFatal((object)"Error! The \"public\" folder does not exist. The overlays will not work. Please report the bug to the mod developer!");
			}
			if (Plugin.ConfigManager.Server_AutoStart.Value)
			{
				Start();
			}
		}

		public static void Start()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			if (IsRunning)
			{
				Plugin.Logger.LogWarning((object)"Server is already running!");
				return;
			}
			try
			{
				IsRunning = true;
				if (!StartHttpServer())
				{
					Plugin.Logger.LogError((object)"Failed to start WebSocket server. HTTP server failed to start.");
					Stop();
					return;
				}
				_webSocketServer = new WebSocketServer($"ws://{IPAddress.Any}:{WebSocketPort}");
				_webSocketServer.AddWebSocketService<OverlayBehavior>("/overlay");
				_webSocketServer.Start();
				if (!_webSocketServer.IsListening)
				{
					Plugin.Logger.LogError((object)"Failed to start WebSocket server. The port might already be in use.");
					Stop();
				}
				else
				{
					Plugin.Logger.LogInfo((object)$"WebSocket server started on ws://localhost:{WebSocketPort}");
				}
			}
			catch (SocketException ex)
			{
				Plugin.Logger.LogError((object)("Failed to start WebSocket server. " + ex.Message));
				Stop();
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to start WebSocket server. {arg}");
				Stop();
			}
		}

		public static void Stop()
		{
			if (IsRunning)
			{
				IsRunning = false;
				if (_httpListener != null)
				{
					_httpListener.Stop();
					_httpListener.Close();
					_httpListener = null;
				}
				WebSocketServer webSocketServer = _webSocketServer;
				if (webSocketServer != null)
				{
					webSocketServer.Stop();
				}
				_webSocketServer = null;
				Plugin.Logger.LogInfo((object)"Server stopped.");
			}
		}

		private static bool StartHttpServer()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			try
			{
				_httpListener = new HttpListener();
				_httpListener.Prefixes.Add($"http://{IPAddress.Any}:{HttpPort}/");
				_httpListener.Start();
				Plugin.Logger.LogInfo((object)$"HTTP server started on http://localhost:{HttpPort}");
				Task.Run((Action)HandleHttpRequests);
				return true;
			}
			catch (SocketException ex)
			{
				Plugin.Logger.LogError((object)("Failed to start HTTP server. " + ex.Message));
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to start HTTP server. {arg}");
			}
			return false;
		}

		private static void HandleHttpRequests()
		{
			while (IsRunning && _httpListener != null)
			{
				try
				{
					IAsyncResult asyncResult = _httpListener.BeginGetContext((AsyncCallback)OnHttpRequest, (object)_httpListener);
					asyncResult.AsyncWaitHandle.WaitOne();
				}
				catch (Exception ex) when (IsRunning)
				{
					Plugin.Logger.LogError((object)("Error handling HTTP requests: " + ex.Message));
				}
			}
		}

		private static void OnHttpRequest(IAsyncResult asyncResult)
		{
			if (_httpListener == null || !_httpListener.IsListening || _isApplicationQuitting)
			{
				return;
			}
			HttpListenerContext context = _httpListener.EndGetContext(asyncResult);
			Task.Run(delegate
			{
				try
				{
					HandleHttpRequest(context);
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogError((object)("Error processing HTTP request: " + ex.Message));
				}
			});
		}

		private static void HandleHttpRequest(HttpListenerContext context)
		{
			HttpListenerRequest request = context.Request;
			HttpListenerResponse response = context.Response;
			try
			{
				string text = request.Url.LocalPath.TrimStart('/');
				Plugin.Instance.LogInfoExtended("Requested path: \"" + text + "\"");
				if (string.IsNullOrEmpty(text))
				{
					text = "overlay.html";
				}
				else if (!Path.HasExtension(text))
				{
					text += ".html";
				}
				if (text.Equals("config.js", StringComparison.OrdinalIgnoreCase))
				{
					response.ContentType = "application/javascript";
					string s = $"const webSocketPort = {WebSocketPort};";
					byte[] bytes = Encoding.UTF8.GetBytes(s);
					response.ContentLength64 = bytes.Length;
					response.OutputStream.Write(bytes, 0, bytes.Length);
					return;
				}
				string path = Path.Combine(Utils.GetPluginDirectoryPath(), "public");
				string text2 = Path.Combine(path, text);
				if (File.Exists(text2))
				{
					string mimeType = GetMimeType(text2);
					response.ContentType = mimeType;
					byte[] array = File.ReadAllBytes(text2);
					response.ContentLength64 = array.Length;
					response.OutputStream.Write(array, 0, array.Length);
				}
				else
				{
					response.StatusCode = 404;
					byte[] bytes2 = Encoding.UTF8.GetBytes("404 - File Not Found");
					response.ContentLength64 = bytes2.Length;
					response.OutputStream.Write(bytes2, 0, bytes2.Length);
				}
			}
			catch (Exception ex)
			{
				response.StatusCode = 500;
				byte[] bytes3 = Encoding.UTF8.GetBytes("500 - Internal Server Error");
				response.ContentLength64 = bytes3.Length;
				response.OutputStream.Write(bytes3, 0, bytes3.Length);
				Plugin.Logger.LogError((object)("Error serving request: " + ex.Message));
			}
			finally
			{
				response.OutputStream.Close();
			}
		}

		private static string GetMimeType(string filePath)
		{
			string text = Path.GetExtension(filePath).ToLower();
			if (1 == 0)
			{
			}
			string result = text switch
			{
				".html" => "text/html", 
				".css" => "text/css", 
				".js" => "application/javascript", 
				".png" => "image/png", 
				".jpg" => "image/jpeg", 
				".jpeg" => "image/jpeg", 
				".gif" => "image/gif", 
				".svg" => "image/svg+xml", 
				".woff" => "font/woff", 
				".woff2" => "font/woff2", 
				".ttf" => "font/ttf", 
				".otf" => "font/otf", 
				".mp3" => "audio/mpeg", 
				".wav" => "audio/wav", 
				".json" => "application/json", 
				_ => "application/octet-stream", 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public static void SendJsonToClients(object jsonData)
		{
			if (_webSocketServer == null || !_webSocketServer.IsListening)
			{
				return;
			}
			lock (_broadcastLock)
			{
				try
				{
					string text = JsonConvert.SerializeObject(jsonData);
					foreach (string path in _webSocketServer.WebSocketServices.Paths)
					{
						WebSocketServiceHost val = _webSocketServer.WebSocketServices[path];
						val.Sessions.Broadcast(text);
					}
				}
				catch (Exception arg)
				{
					Plugin.Logger.LogError((object)$"Failed to send JSON data to WebSocket clients. {arg}");
				}
			}
		}

		public static void UpdateOverlays()
		{
			UpdateOverlaysFormatting();
			UpdateOverlaysData();
		}

		public static void UpdateOverlaysFormatting()
		{
			SendJsonToClients(GetOverlaysFormatting());
		}

		public static void UpdateOverlaysData()
		{
			SendJsonToClients(GetOverlaysData());
		}

		public static object GetOverlaysFormatting()
		{
			return new
			{
				type = "formatting",
				crewLabel = Plugin.ConfigManager.CrewStat_Label.Value,
				moonLabel = Plugin.ConfigManager.MoonStat_Label.Value,
				dayLabel = Plugin.ConfigManager.DayStat_Label.Value,
				quotaLabel = Plugin.ConfigManager.QuotaStat_Label.Value,
				lootLabel = Plugin.ConfigManager.LootStat_Label.Value,
				averagePerDayLabel = Plugin.ConfigManager.AveragePerDayStat_Label.Value
			};
		}

		public static object GetOverlaysData()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			return new
			{
				type = "data",
				showOverlay = Utils.CanShowOverlay(),
				crewCount = Utils.GetPlayerCount(),
				moonName = Utils.GetCurrentPlanetName(),
				weatherName = Utils.GetEnumName<LevelWeatherType>(Utils.GetCurrentPlanetWeather()),
				showWeatherIcon = Plugin.ConfigManager.MoonStat_ShowWeatherIcon.Value,
				dayCount = DayManager.GetDayNumber(),
				dayInQuota = Utils.GetDayInQuota(),
				quotaValue = Utils.GetProfitQuota(),
				quotaIndex = Utils.GetQuotaIndex(),
				lootValue = LootManager.GetLootTotal(),
				averagePerDayValue = DayManager.GetAveragePerDay()
			};
		}

		private static bool WebsiteFolderExists()
		{
			return Directory.Exists(GetWebsiteFolderPath());
		}

		private static bool WebsiteArchiveExists()
		{
			return File.Exists(GetWebsiteArchivePath());
		}

		private static async Task DecompressWebsiteArchive()
		{
			string archivePath = GetWebsiteArchivePath();
			if (!File.Exists(archivePath))
			{
				return;
			}
			try
			{
				string extractPath = Utils.GetPluginDirectoryPath();
				await Task.Run(delegate
				{
					using ZipArchive zipArchive = ZipFile.OpenRead(archivePath);
					foreach (ZipArchiveEntry entry in zipArchive.Entries)
					{
						string text = Path.Combine(extractPath, entry.FullName);
						string directoryName = Path.GetDirectoryName(text);
						if (!string.IsNullOrEmpty(directoryName))
						{
							Directory.CreateDirectory(directoryName);
						}
						if (!entry.FullName.EndsWith("/"))
						{
							entry.ExtractToFile(text, overwrite: true);
						}
					}
				});
				File.Delete(archivePath);
				Plugin.Logger.LogInfo((object)"Successfully decompressed public archive.");
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Error while decompressing public archive: " + ex.Message));
			}
		}

		private static string GetWebsiteFolderPath()
		{
			return Path.Combine(Utils.GetPluginDirectoryPath(), "public");
		}

		private static string GetWebsiteArchivePath()
		{
			return Path.Combine(Utils.GetPluginDirectoryPath(), "public.zip");
		}
	}
}
namespace com.github.zehsteam.StreamOverlays.Patches
{
	[HarmonyPatch(typeof(DepositItemsDesk))]
	internal static class DepositItemsDeskPatch
	{
		[HarmonyPatch("SellAndDisplayItemProfits")]
		[HarmonyPostfix]
		private static void SellAndDisplayItemProfitsPatch()
		{
			if (LootManager.CanUpdateLootTotal())
			{
				LootManager.UpdateLootTotal();
				WebServer.UpdateOverlaysData();
			}
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager))]
	internal static class GameNetworkManagerPatch
	{
		[HarmonyPatch("SaveGame")]
		[HarmonyPostfix]
		private static void SaveGamePatch()
		{
			DayManager.SaveDayData();
			LootManager.UpdateLootTotal();
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("ResetSavedGameValues")]
		[HarmonyPostfix]
		private static void ResetSavedGameValuesPatch()
		{
			DayManager.ResetSavedDayData();
			WebServer.UpdateOverlaysData();
		}
	}
	[HarmonyPatch(typeof(NetworkManager))]
	internal static class NetworkManagerPatch
	{
		[HarmonyPatch("Initialize")]
		[HarmonyPostfix]
		private static void InitializePatch()
		{
			PluginNetworkManager.Initialize();
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal static class PlayerControllerBPatch
	{
		[HarmonyPatch("ConnectClientToPlayerObject")]
		[HarmonyPostfix]
		private static void ConnectClientToPlayerObjectPatch()
		{
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("GrabObjectClientRpc")]
		[HarmonyPostfix]
		private static void GrabObjectClientRpcPatch(NetworkObjectReference grabbedObject)
		{
			NetworkObject val = default(NetworkObject);
			GrabbableObject val2 = default(GrabbableObject);
			if (LootManager.CanUpdateLootTotal() && ((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null) && ((Component)val).TryGetComponent<GrabbableObject>(ref val2) && (val2.isInShipRoom || val2.isInElevator))
			{
				LootManager.UpdateLootTotal();
				WebServer.UpdateOverlaysData();
			}
		}

		[HarmonyPatch("ThrowObjectClientRpc")]
		[HarmonyPostfix]
		private static void ThrowObjectClientRpcPatch(bool droppedInElevator, bool droppedInShipRoom)
		{
			if (LootManager.CanUpdateLootTotal() && (droppedInShipRoom || droppedInElevator))
			{
				LootManager.UpdateLootTotal();
				WebServer.UpdateOverlaysData();
			}
		}

		[HarmonyPatch("PlaceGrabbableObject")]
		[HarmonyPostfix]
		private static void PlaceGrabbableObjectPatch(GrabbableObject placeObject)
		{
			if (LootManager.CanUpdateLootTotal() && !((Object)(object)placeObject == (Object)null) && (placeObject.isInShipRoom || placeObject.isInElevator))
			{
				LootManager.UpdateLootTotal();
				WebServer.UpdateOverlaysData();
			}
		}
	}
	[HarmonyPatch(typeof(RoundManager))]
	internal static class RoundManagerPatch
	{
		[HarmonyPatch("DespawnPropsAtEndOfRound")]
		[HarmonyPostfix]
		private static void DespawnPropsAtEndOfRoundPatch()
		{
			LootManager.UpdateLootTotal();
			WebServer.UpdateOverlaysData();
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal static class StartOfRoundPatch
	{
		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void StartPatch()
		{
			DayManager.LoadDayData();
			LootManager.UpdateLootTotal();
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("OnPlayerConnectedClientRpc")]
		[HarmonyPostfix]
		private static void OnPlayerConnectedClientRpcPatch()
		{
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("SyncShipUnlockablesClientRpc")]
		[HarmonyPostfix]
		private static void SyncShipUnlockablesClientRpcPatch()
		{
			LootManager.UpdateLootTotal();
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("OnClientConnect")]
		[HarmonyPostfix]
		private static void OnClientConnectPatch(ulong clientId)
		{
			WebServer.UpdateOverlaysData();
			PluginNetworkManager.OnClientConnected(clientId);
		}

		[HarmonyPatch("OnPlayerDC")]
		[HarmonyPostfix]
		private static void OnPlayerDCPatch()
		{
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("ChangeLevelClientRpc")]
		[HarmonyPostfix]
		private static void ChangeLevelClientRpcPatch()
		{
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("StartGame")]
		[HarmonyPostfix]
		private static void StartGamePatch()
		{
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("EndOfGame")]
		[HarmonyPostfix]
		private static void EndOfGamePatch()
		{
			DayManager.AddDayData(Utils.GetScrapValueCollectedThisRound());
			LootManager.UpdateLootTotal();
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("ReviveDeadPlayers")]
		[HarmonyPostfix]
		private static void ReviveDeadPlayersPatch()
		{
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("SetMapScreenInfoToCurrentLevel")]
		[HarmonyPostfix]
		private static void SetMapScreenInfoToCurrentLevelPatch()
		{
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("ResetShip")]
		[HarmonyPostfix]
		private static void ResetShipPatch()
		{
			LootManager.UpdateLootTotal();
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("OnLocalDisconnect")]
		[HarmonyPostfix]
		private static void OnLocalDisconnectPatch()
		{
			WebServer.UpdateOverlaysData();
		}
	}
	[HarmonyPatch(typeof(TimeOfDay))]
	internal static class TimeOfDayPatch
	{
		[HarmonyPatch("SyncNewProfitQuotaClientRpc")]
		[HarmonyPostfix]
		private static void SyncNewProfitQuotaClientRpcPatch()
		{
			WebServer.UpdateOverlaysData();
		}

		[HarmonyPatch("UpdateProfitQuotaCurrentTime")]
		[HarmonyPostfix]
		private static void UpdateProfitQuotaCurrentTimePatch()
		{
			LootManager.UpdateLootTotal();
			WebServer.UpdateOverlaysData();
		}
	}
	[HarmonyPatch(typeof(VehicleController))]
	internal static class VehicleControllerPatch
	{
		[HarmonyPatch("CollectItemsInTruck")]
		[HarmonyPostfix]
		private static void CollectItemsInTruckPatch()
		{
			if (LootManager.CanUpdateLootTotal())
			{
				LootManager.UpdateLootTotal();
				WebServer.UpdateOverlaysData();
			}
		}
	}
}
namespace com.github.zehsteam.StreamOverlays.Helpers
{
	internal static class ConfigHelper
	{
		public static void SkipAutoGen()
		{
			if (LethalConfigProxy.Enabled)
			{
				LethalConfigProxy.SkipAutoGen();
			}
		}

		public static void AddButton(string section, string name, string description, string buttonText, Action callback)
		{
			if (LethalConfigProxy.Enabled)
			{
				LethalConfigProxy.AddButton(section, name, description, buttonText, callback);
			}
		}

		public static ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, bool requiresRestart, string description, AcceptableValueBase acceptableValues = null, Action<T> settingChanged = null, ConfigFile configFile = null)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			if (configFile == null)
			{
				configFile = Plugin.Config;
			}
			ConfigEntry<T> configEntry = ((acceptableValues == null) ? configFile.Bind<T>(section, key, defaultValue, description) : configFile.Bind<T>(section, key, defaultValue, new ConfigDescription(description, acceptableValues, Array.Empty<object>())));
			if (settingChanged != null)
			{
				configEntry.SettingChanged += delegate
				{
					settingChanged?.Invoke(configEntry.Value);
				};
			}
			if (LethalConfigProxy.Enabled)
			{
				LethalConfigProxy.AddConfig<T>(configEntry, requiresRestart);
			}
			return configEntry;
		}

		public static Dictionary<ConfigDefinition, string> GetOrphanedConfigEntries(ConfigFile configFile = null)
		{
			if (configFile == null)
			{
				configFile = Plugin.Config;
			}
			PropertyInfo property = ((object)configFile).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic);
			return (Dictionary<ConfigDefinition, string>)property.GetValue(configFile, null);
		}

		public static void SetConfigEntryValue<T>(ConfigEntry<T> configEntry, string value)
		{
			if (typeof(T) == typeof(int) && int.TryParse(value, out var result))
			{
				configEntry.Value = (T)(object)result;
				return;
			}
			if (typeof(T) == typeof(float) && float.TryParse(value, out var result2))
			{
				configEntry.Value = (T)(object)result2;
				return;
			}
			if (typeof(T) == typeof(double) && double.TryParse(value, out var result3))
			{
				configEntry.Value = (T)(object)result3;
				return;
			}
			if (typeof(T) == typeof(bool) && bool.TryParse(value, out var result4))
			{
				configEntry.Value = (T)(object)result4;
				return;
			}
			if (typeof(T) == typeof(string))
			{
				configEntry.Value = (T)(object)value;
				return;
			}
			throw new InvalidOperationException($"Unsupported type: {typeof(T)}");
		}

		public static void ClearUnusedEntries(ConfigFile configFile = null)
		{
			if (configFile == null)
			{
				configFile = Plugin.Config;
			}
			Dictionary<ConfigDefinition, string> orphanedConfigEntries = GetOrphanedConfigEntries(configFile);
			if (orphanedConfigEntries != null)
			{
				orphanedConfigEntries.Clear();
				configFile.Save();
			}
		}
	}
	internal static class GrabbableObjectHelper
	{
		private static readonly FieldInfo _deactivatedField;

		static GrabbableObjectHelper()
		{
			_deactivatedField = typeof(GrabbableObject).GetField("deactivated", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		}

		public static bool IsDeactivated(GrabbableObject grabbableObject)
		{
			if (_deactivatedField != null)
			{
				return (_deactivatedField.GetValue(grabbableObject) as bool?).GetValueOrDefault();
			}
			return false;
		}
	}
}
namespace com.github.zehsteam.StreamOverlays.Dependencies
{
	internal static class LethalConfigProxy
	{
		public const string PLUGIN_GUID = "ainavt.lc.lethalconfig";

		private static bool? _enabled;

		public static bool Enabled
		{
			get
			{
				bool valueOrDefault = _enabled.GetValueOrDefault();
				if (!_enabled.HasValue)
				{
					valueOrDefault = Chainloader.PluginInfos.ContainsKey("ainavt.lc.lethalconfig");
					_enabled = valueOrDefault;
				}
				return _enabled.Value;
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static void SkipAutoGen()
		{
			LethalConfigManager.SkipAutoGen();
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static void AddConfig<T>(ConfigEntry<T> configEntry, bool requiresRestart = false)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			AcceptableValueBase acceptableValues = ((ConfigEntryBase)configEntry).Description.AcceptableValues;
			if (acceptableValues != null)
			{
				if (acceptableValues is AcceptableValueRange<float> || acceptableValues is AcceptableValueRange<int>)
				{
					AddConfigSlider<T>(configEntry, requiresRestart);
					return;
				}
				if (acceptableValues is AcceptableValueList<string>)
				{
					AddConfigDropdown<T>(configEntry, requiresRestart);
					return;
				}
			}
			if (!(configEntry is ConfigEntry<string> val))
			{
				if (!(configEntry is ConfigEntry<bool> val2))
				{
					if (!(configEntry is ConfigEntry<float> val3))
					{
						if (!(configEntry is ConfigEntry<int> val4))
						{
							throw new NotSupportedException($"Unsupported type: {typeof(T)}");
						}
						LethalConfigManager.AddConfigItem((BaseConfigItem)new IntInputFieldConfigItem(val4, requiresRestart));
					}
					else
					{
						LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatInputFieldConfigItem(val3, requiresRestart));
					}
				}
				else
				{
					LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(val2, requiresRestart));
				}
			}
			else
			{
				LethalConfigManager.AddConfigItem((BaseConfigItem)new TextInputFieldConfigItem(val, requiresRestart));
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static void AddConfigSlider<T>(ConfigEntry<T> configEntry, bool requiresRestart = false)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			if (!(configEntry is ConfigEntry<float> val))
			{
				if (!(configEntry is ConfigEntry<int> val2))
				{
					throw new NotSupportedException($"Slider not supported for type: {typeof(T)}");
				}
				LethalConfigManager.AddConfigItem((BaseConfigItem)new IntSliderConfigItem(val2, requiresRestart));
			}
			else
			{
				LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(val, requiresRestart));
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static void AddConfigDropdown<T>(ConfigEntry<T> configEntry, bool requiresRestart = false)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			if (configEntry is ConfigEntry<string> val)
			{
				LethalConfigManager.AddConfigItem((BaseConfigItem)new TextDropDownConfigItem(val, requiresRestart));
				return;
			}
			throw new NotSupportedException($"Dropdown not supported for type: {typeof(T)}");
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static void AddButton(string section, string name, string description, string buttonText, Action callback)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			LethalConfigManager.AddConfigItem((BaseConfigItem)new GenericButtonConfigItem(section, name, description, buttonText, (GenericButtonHandler)delegate
			{
				callback?.Invoke();
			}));
		}
	}
}
namespace com.github.zehsteam.StreamOverlays.Dependencies.Vanilla
{
	internal static class VehicleControllerProxy
	{
		private static bool? _enabled;

		public static bool Enabled
		{
			get
			{
				bool valueOrDefault = _enabled.GetValueOrDefault();
				if (!_enabled.HasValue)
				{
					valueOrDefault = GetEnabledState();
					_enabled = valueOrDefault;
				}
				return _enabled.Value;
			}
		}

		private static bool GetEnabledState()
		{
			try
			{
				Assembly assembly = typeof(StartOfRound).Assembly;
				return assembly.GetType("VehicleController") != null;
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to get enabled state from VehicleControllerProxy. {arg}");
				return false;
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static void PatchAll(Harmony harmony)
		{
			try
			{
				harmony.PatchAll(typeof(VehicleControllerPatch));
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to apply VehicleController patch. {arg}");
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static int GetLootTotal()
		{
			if ((Object)(object)StartOfRound.Instance == (Object)null)
			{
				return 0;
			}
			try
			{
				VehicleController attachedVehicle = StartOfRound.Instance.attachedVehicle;
				if ((Object)(object)attachedVehicle == (Object)null)
				{
					return 0;
				}
				GrabbableObject[] componentsInChildren = ((Component)attachedVehicle).GetComponentsInChildren<GrabbableObject>();
				return componentsInChildren.Where(Utils.IsValidScrapAndNotHeld).Sum((GrabbableObject x) => x.scrapValue);
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to get loot total from attached vehicle. {arg}");
				return 0;
			}
		}
	}
}
namespace com.github.zehsteam.StreamOverlays.Dependencies.ShipInventoryProxy
{
	internal static class ShipInventoryProxy
	{
		public const string PLUGIN_GUID = "ShipInventory";

		private static bool? _enabled;

		public static bool Enabled
		{
			get
			{
				bool valueOrDefault = _enabled.GetValueOrDefault();
				if (!_enabled.HasValue)
				{
					valueOrDefault = Chainloader.PluginInfos.ContainsKey("ShipInventory");
					_enabled = valueOrDefault;
				}
				return _enabled.Value;
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static void PatchAll(Harmony harmony)
		{
			try
			{
				harmony.PatchAll(typeof(ItemManagerPatch));
				harmony.PatchAll(typeof(ChuteInteractPatch));
				Plugin.Logger.LogInfo((object)"Applied ShipInventory patches.");
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to apply ShipInventory patches. {arg}");
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		public static int GetLootTotal(bool onlyFromRound = false)
		{
			try
			{
				return ItemManager.GetTotalValue(true, onlyFromRound);
			}
			catch (Exception arg)
			{
				Plugin.Logger.LogError((object)$"Failed to get the total value from ShipInventory. {arg}");
			}
			return 0;
		}
	}
}
namespace com.github.zehsteam.StreamOverlays.Dependencies.ShipInventoryProxy.Patches
{
	[HarmonyPatch(typeof(ChuteInteract))]
	internal static class ChuteInteractPatch
	{
		[HarmonyPatch("SpawnItemClientRpc")]
		[HarmonyPostfix]
		private static void SpawnItemClientRpcPatch()
		{
			if (LootManager.CanUpdateLootTotal())
			{
				LootManager.UpdateLootTotal();
				WebServer.UpdateOverlaysData();
			}
		}
	}
	[HarmonyPatch(typeof(ItemManager))]
	internal static class ItemManagerPatch
	{
		[HarmonyPatch("UpdateCache")]
		[HarmonyPostfix]
		private static void UpdateCachePatch()
		{
			if (LootManager.CanUpdateLootTotal())
			{
				LootManager.UpdateLootTotal();
				WebServer.UpdateOverlaysData();
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}