Decompiled source of Quick Buy Menu v2.0.0

BepInEx/plugins/QuickBuyMenu.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CSync.Lib;
using CSync.Util;
using GameNetcodeStuff;
using HarmonyLib;
using LC_API.ClientAPI;
using LC_API.GameInterfaceAPI.Features;
using LethalNetworkAPI;
using Microsoft.CodeAnalysis;
using TMPro;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("QuickBuyMenu")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("An experimental mod for providing an alternative means to purchase handheld items instantly from the Terminal.")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0")]
[assembly: AssemblyProduct("Quick Buy Menu")]
[assembly: AssemblyTitle("QuickBuyMenu")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.0.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 QuickBuyMenu
{
	[BepInPlugin("Quick.Buy.Menu", "Quick Buy Meny", "2.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public struct ClientItemRequestParams : INetworkSerializeByMemcpy
		{
			public string ItemName;

			public int clientIndex;

			private unsafe void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				serializer.SerializeValue(ref ItemName, false);
				((BufferSerializer<int>*)(&serializer))->SerializeValue<int>(ref clientIndex, default(ForPrimitives));
			}
		}

		private static Plugin Instance;

		internal static ManualLogSource Log;

		private LNetworkMessage<ClientItemRequestParams> clientItemSpawnRequest;

		private LNetworkMessage<int> syncCredits;

		private List<string> blackListedItems;

		public static QuickBuyModConfig Config { get; private set; }

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogDebug((object)"Plugin QuickBuyMenu is loaded!");
			Config = new QuickBuyModConfig(((BaseUnityPlugin)this).Config);
			blackListedItems = (from item in Config.quickBuyItemBlacklist.Value.Split(',')
				select item.Trim() into item
				where !string.IsNullOrEmpty(item)
				select item).ToList();
			CommandHandler.RegisterCommand("quickbuy", new List<string> { "qb", "buy", "qbuy" }, (Action<string[]>)RunQuickBuy);
			CommandHandler.RegisterCommand("price-check", new List<string> { "qc", "inquire", "check", "pc" }, (Action<string[]>)RunPriceCheck);
			clientItemSpawnRequest = LNetworkMessage<ClientItemRequestParams>.Create("clientItemSpawnRequest", (Action<ClientItemRequestParams, ulong>)delegate(ClientItemRequestParams clientRequest, ulong clientId)
			{
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				Player val = Player.Get(GameNetworkManager.Instance.localPlayerController.playersManager.allPlayerScripts[clientRequest.clientIndex]);
				GameObject spawnPrefab = ((IEnumerable<Item>)Object.FindObjectOfType<Terminal>().buyableItemsList).FirstOrDefault((Func<Item, bool>)((Item kw) => ((Object)kw).name.Equals(clientRequest.ItemName))).spawnPrefab;
				if ((Object)(object)spawnPrefab != (Object)null)
				{
					GameObject val2 = Object.Instantiate<GameObject>(spawnPrefab, Vector3.zero, default(Quaternion));
					val2.GetComponent<NetworkObject>().Spawn(false);
					Item component = val2.GetComponent<Item>();
					component.GiveTo(val, true);
				}
			}, (Action<ClientItemRequestParams>)null, (Action<ClientItemRequestParams, ulong>)null);
			syncCredits = LNetworkMessage<int>.Create("syncCredits", (Action<int, ulong>)delegate(int credits, ulong clientId)
			{
				((BaseUnityPlugin)this).Logger.LogDebug((object)$"Server received update credits: {credits}");
				Object.FindObjectOfType<Terminal>().groupCredits = credits;
			}, (Action<int>)delegate(int credits)
			{
				((BaseUnityPlugin)this).Logger.LogDebug((object)$"Client received update credits: {credits}");
				Object.FindObjectOfType<Terminal>().groupCredits = credits;
			}, (Action<int, ulong>)delegate(int credits, ulong clientId)
			{
				((BaseUnityPlugin)this).Logger.LogDebug((object)$"Client - client received update credits: {credits}");
				Object.FindObjectOfType<Terminal>().groupCredits = credits;
			});
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
		}

		private void RunQuickBuy(string[] obj)
		{
			Terminal val = Object.FindObjectOfType<Terminal>();
			if (!IsQuickBuyAllowed())
			{
				chatMessageHandler("You can only use quick buy commands on the ship.", isWarning: true);
			}
			else
			{
				if (obj.Length == 0)
				{
					return;
				}
				int quantity = GetQuantity(obj);
				string text = obj[0].Trim();
				((BaseUnityPlugin)this).Logger.LogDebug((object)(" item arg: " + obj[0]));
				Item itemMatch = FindItemMatch(val, text);
				if ((Object)(object)itemMatch == (Object)null)
				{
					chatMessageHandler("Item " + text + " not found.", isWarning: true);
				}
				else if (blackListedItems.Exists((string item) => item.Equals(itemMatch.itemName, StringComparison.OrdinalIgnoreCase)))
				{
					chatMessageHandler(itemMatch.itemName + " is blacklisted.", isWarning: true);
				}
				else if (CheckPlayerInventory(quantity))
				{
					if (!HasEnoughCredits(val, itemMatch, quantity, out var itemCost, out var adjustedCredits))
					{
						chatMessageHandler($"Not Enough Credits\n\nTotal Cost: ${itemCost}\nCredits: ${val.groupCredits}", isWarning: true);
					}
					else
					{
						ProcessQuickBuy(val, itemMatch, quantity, itemCost, adjustedCredits);
					}
				}
			}
		}

		private void RunPriceCheck(string[] obj)
		{
			Terminal val = Object.FindObjectOfType<Terminal>();
			if (!IsQuickBuyAllowed())
			{
				chatMessageHandler("You can only use quick buy commands on the ship.", isWarning: true);
			}
			else if (obj.Length != 0)
			{
				string text = obj[0].Trim();
				int quantity = GetQuantity(obj);
				Item itemMatch = FindItemMatch(val, text);
				float itemCost;
				int adjustedCredits;
				if ((Object)(object)itemMatch == (Object)null)
				{
					chatMessageHandler("Item " + text + " not found.", isWarning: true);
				}
				else if (blackListedItems.Exists((string item) => item.Equals(itemMatch.itemName, StringComparison.OrdinalIgnoreCase)))
				{
					chatMessageHandler(itemMatch.itemName + " is blacklisted.", isWarning: true);
				}
				else if (!HasEnoughCredits(val, itemMatch, quantity, out itemCost, out adjustedCredits))
				{
					chatMessageHandler($"Price Check\nNot Enough Credits\n\nItem: {itemMatch.itemName}\nQuantity: {quantity}\nTotal Cost: ${itemCost}\nGroup Credits: ${val.groupCredits}", isWarning: true);
				}
				else
				{
					chatMessageHandler($"Price Check\n\nItem: {itemMatch.itemName}\nQuantity: {quantity}\nTotal Cost: ${itemCost}\nGroup Credits: ${val.groupCredits}");
				}
			}
		}

		private bool IsQuickBuyAllowed()
		{
			return Config.allowQuickBuyOffShip.Value || GameNetworkManager.Instance.localPlayerController.isInHangarShipRoom;
		}

		private int GetQuantity(string[] obj)
		{
			int result;
			return (obj.Length != 2 || !int.TryParse(obj[1], out result)) ? 1 : result;
		}

		private Item FindItemMatch(Terminal terminal, string itemKeyword)
		{
			return ((IEnumerable<Item>)terminal.buyableItemsList).FirstOrDefault((Func<Item, bool>)((Item kw) => ((Object)kw).name.Contains(itemKeyword, StringComparison.OrdinalIgnoreCase))) ?? ((IEnumerable<Item>)terminal.buyableItemsList).FirstOrDefault((Func<Item, bool>)((Item kw) => ((Object)kw).name.Equals(itemKeyword, StringComparison.OrdinalIgnoreCase)));
		}

		private bool HasEnoughCredits(Terminal terminal, Item itemMatch, int quantity, out float itemCost, out int adjustedCredits)
		{
			itemCost = (float)itemMatch.creditsWorth * ((float)terminal.itemSalesPercentages[Array.IndexOf(terminal.buyableItemsList, itemMatch)] / 100f) * (float)quantity;
			adjustedCredits = terminal.groupCredits - (int)itemCost;
			return adjustedCredits >= 0;
		}

		private bool CheckPlayerInventory(int quantity)
		{
			Player val = Player.Get(GameNetworkManager.Instance.localPlayerController);
			if (val.Inventory.GetFirstEmptySlot() == -1)
			{
				chatMessageHandler("Inventory is Full.", isWarning: true);
				return false;
			}
			Log.LogDebug((object)$"Item slots length: {val.PlayerController.ItemSlots.Length}");
			int num = val.Inventory.Items.Where((Item item) => (Object)(object)item != (Object)null).ToArray().Length;
			int num2 = val.PlayerController.ItemSlots.Length - num;
			if (quantity > val.PlayerController.ItemSlots.Length - num)
			{
				chatMessageHandler("Not enough inventory space for this order.", isWarning: true);
				return false;
			}
			return true;
		}

		private void ProcessQuickBuy(Terminal terminal, Item itemMatch, int quantity, float itemCost, int adjustedCredits)
		{
			int clientIndex = Array.FindIndex(GameNetworkManager.Instance.localPlayerController.playersManager.allPlayerScripts, (PlayerControllerB player) => player.actualClientId.Equals(GameNetworkManager.Instance.localPlayerController.actualClientId));
			for (int i = 0; i < quantity; i++)
			{
				ClientItemRequestParams clientItemRequestParams = default(ClientItemRequestParams);
				clientItemRequestParams.clientIndex = clientIndex;
				clientItemRequestParams.ItemName = ((Object)itemMatch).name;
				clientItemSpawnRequest.SendServer(clientItemRequestParams);
			}
			terminal.groupCredits = adjustedCredits;
			SyncCredits(adjustedCredits);
			chatMessageHandler($"Order Summary\n\n{itemMatch.itemName}\nQuantity: {quantity}\nTotal: ${(int)itemCost}\nCredits: ${adjustedCredits}");
		}

		private void SyncCredits(int adjustedCredits)
		{
			if (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer)
			{
				syncCredits.SendClients(adjustedCredits);
			}
			else
			{
				syncCredits.SendOtherClients(adjustedCredits);
			}
		}

		private void chatMessageHandler(string message, bool isWarning = false)
		{
			string text = (isWarning ? "red" : "green");
			string text2 = "<color=\"" + text + "\"><b>Quick Buy</b>\n" + message + "</color>";
			if (HUDManager.Instance.lastChatMessage == text2)
			{
				HUDManager.Instance.lastChatMessage = "";
			}
			HUDManager.Instance.AddChatMessage(text2, "");
			AudioClip[] array = (isWarning ? HUDManager.Instance.warningSFX : HUDManager.Instance.tipsSFX);
			RoundManager.PlayRandomClip(HUDManager.Instance.UIAudio, array, false, 1f, 0, 1000);
			quickBuyChatMessageDelayHandler(Config.quickBuyMessagesFadeDelay.Value);
		}

		private async void quickBuyChatMessageDelayHandler(int seconds)
		{
			await Task.Delay(seconds * 1000);
			int chatIndex = HUDManager.Instance.ChatMessageHistory.FindIndex((string chat) => chat.Contains("<b>Quick Buy</b>"));
			if (chatIndex != -1)
			{
				HUDManager.Instance.ChatMessageHistory.RemoveAt(chatIndex);
				((TMP_Text)HUDManager.Instance.chatText).text = "";
				for (int i = 0; i < HUDManager.Instance.ChatMessageHistory.Count; i++)
				{
					TextMeshProUGUI textMeshProUGUI = HUDManager.Instance.chatText;
					((TMP_Text)textMeshProUGUI).text = ((TMP_Text)textMeshProUGUI).text + "\n" + HUDManager.Instance.ChatMessageHistory[i];
				}
			}
		}
	}
	[DataContract]
	public class QuickBuyModConfig : SyncedConfig<QuickBuyModConfig>
	{
		[DataMember]
		public SyncedEntry<bool> allowQuickBuyOffShip { get; private set; }

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

		[DataMember]
		public SyncedEntry<string> quickBuyItemBlacklist { get; private set; }

		[DataMember]
		public SyncedEntry<float> EXAMPLE_VAR { get; private set; }

		public QuickBuyModConfig(ConfigFile cfg)
			: base("Quick Buy Menu")
		{
			ConfigManager.Register<QuickBuyModConfig>(this);
			allowQuickBuyOffShip = Extensions.BindSyncedEntry<bool>(cfg, "General", "AllowQuickBuyOffShip", false, "Boolean that lets you buy items off ship.  For balancing this is set to false as default.");
			quickBuyMessagesFadeDelay = cfg.Bind<int>("General", "quickBuyMessagesFadeDelay", 5, "Timer in seconds for how long the Quick Buy chat messages should appear before they are deleted.");
			quickBuyItemBlacklist = Extensions.BindSyncedEntry<string>(cfg, "General", "QuickBuyItemBlacklist", "", "Comma Seperated List of Items to be blacklisted by Quick Buy.  Example: 'Walkie-Talkie,FlashLight,Boombox'");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "QuickBuyMenu";

		public const string PLUGIN_NAME = "Quick Buy Menu";

		public const string PLUGIN_VERSION = "2.0.0";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}