Decompiled source of DropshipItemRecovery v1.0.3

DropshipItemRecovery.dll

Decompiled 3 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
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: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("DropshipItemRecovery")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("This mod solves the problem that occurs when the host player disconnects from the game after ordering items from the store in the terminal.")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3")]
[assembly: AssemblyProduct("DropshipItemRecovery")]
[assembly: AssemblyTitle("DropshipItemRecovery")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.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 DropshipItemRecovery
{
	public static class BuyItemsServerRpcPatch
	{
		[Serializable]
		private class SaveData
		{
			public List<int> OrderedItems = new List<int>();

			public int BalanceSpent = 0;

			public int lastFullBalance = 0;

			public bool hasWarrantyTicket = false;

			public bool vehicleInDropship = false;

			public int orderedVehicleFromTerminal = 0;

			public Item[] buyableItemsFromTerminal = Array.Empty<Item>();
		}

		private static readonly string SavePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		private static readonly byte[] EncKey = Encoding.UTF8.GetBytes("hrdb_xkey");

		private static float _lastSaveTime = -999f;

		[HarmonyPatch(typeof(Terminal), "LoadNewNodeIfAffordable")]
		[HarmonyPrefix]
		public static void BeforePurchases(Terminal __instance, out int __state)
		{
			__state = __instance.orderedItemsFromTerminal.Count;
		}

		[HarmonyPatch(typeof(Terminal), "LoadNewNodeIfAffordable")]
		[HarmonyPostfix]
		public static void SavePurchases(Terminal __instance, TerminalNode node, int __state)
		{
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsHost)
			{
				return;
			}
			int num = __instance.orderedItemsFromTerminal.Count - __state;
			if (node.buyItemIndex != -1 && num > 0)
			{
				float num2 = (float)__instance.itemSalesPercentages[node.buyItemIndex] / 100f;
				int num3 = (int)Math.Round((float)node.itemCost * num2);
				SaveData saveData = LoadSaveData();
				for (int i = 0; i < num; i++)
				{
					saveData.OrderedItems.Add(node.buyItemIndex);
					saveData.BalanceSpent += num3;
					saveData.lastFullBalance = __instance.groupCredits;
				}
				saveData.buyableItemsFromTerminal = __instance.buyableItemsList;
				SaveDataToFile(saveData);
			}
		}

		[HarmonyPatch(typeof(Terminal), "BuyItemsServerRpc")]
		[HarmonyPrefix]
		public static void HandleClientPurchase(Terminal __instance, int[] boughtItems, int newGroupCredits, int numItemsInShip)
		{
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsHost)
			{
				return;
			}
			try
			{
				SaveData saveData = LoadSaveData();
				foreach (int num in boughtItems)
				{
					int num2 = 0;
					if (num < __instance.buyableItemsList.Length)
					{
						num2 = __instance.buyableItemsList[num].creditsWorth;
					}
					else
					{
						int num3 = num - __instance.buyableItemsList.Length;
						if (num3 >= 0 && num3 < __instance.buyableVehicles.Length)
						{
							num2 = __instance.buyableVehicles[num3].creditsWorth;
						}
					}
					float num4 = (float)__instance.itemSalesPercentages[num] / 100f;
					int num5 = (int)Math.Round((float)num2 * num4);
					saveData.OrderedItems.Add(num);
					saveData.BalanceSpent += num5;
					saveData.lastFullBalance = __instance.groupCredits;
				}
				SaveDataToFile(saveData);
			}
			catch (Exception arg)
			{
				Plugin.Instance.SendLog($"Failed to save purchases on host in BuyItemsServerRpc: {arg}");
			}
		}

		[HarmonyPatch(typeof(Terminal), "Start")]
		[HarmonyPostfix]
		public static void AwakePost(Terminal __instance)
		{
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsHost)
			{
				return;
			}
			SaveData saveData = LoadSaveData();
			__instance.orderedItemsFromTerminal.Clear();
			int groupCredits = __instance.groupCredits;
			int lastFullBalance = saveData.lastFullBalance;
			if (saveData.OrderedItems.Count > 0)
			{
				__instance.numberOfItemsInDropship = saveData.OrderedItems.Count;
				__instance.orderedItemsFromTerminal.AddRange(saveData.OrderedItems);
				if (__instance.groupCredits >= lastFullBalance)
				{
					HUDManager.Instance.DisplayTip("DropshipItemRecovery", "Credits are corrupted. Restoring...", false, false, "LC_Tip1");
					__instance.groupCredits = groupCredits - saveData.BalanceSpent;
				}
			}
			else if (saveData.vehicleInDropship)
			{
				__instance.vehicleInDropship = saveData.vehicleInDropship;
				__instance.hasWarrantyTicket = saveData.hasWarrantyTicket;
				__instance.orderedVehicleFromTerminal = saveData.orderedVehicleFromTerminal;
				if (__instance.groupCredits >= lastFullBalance)
				{
					HUDManager.Instance.DisplayTip("DropshipItemRecovery", "Credits are corrupted. Restoring...", false, false, "LC_Tip1");
					__instance.groupCredits = groupCredits - saveData.BalanceSpent;
				}
			}
		}

		[HarmonyPatch(typeof(Terminal), "BuyVehicleClientRpc")]
		[HarmonyPostfix]
		public static void BuyVehicleClientRpc(Terminal __instance)
		{
			if (!((Object)(object)NetworkManager.Singleton != (Object)null) || !NetworkManager.Singleton.IsHost || Time.time - _lastSaveTime < 0.5f)
			{
				return;
			}
			_lastSaveTime = Time.time;
			try
			{
				SaveData saveData = LoadSaveData();
				if (saveData.OrderedItems.Count <= 0)
				{
					saveData.hasWarrantyTicket = __instance.hasWarrantyTicket;
					saveData.vehicleInDropship = __instance.vehicleInDropship;
					saveData.orderedVehicleFromTerminal = __instance.orderedVehicleFromTerminal;
					int orderedVehicleFromTerminal = __instance.orderedVehicleFromTerminal;
					if (orderedVehicleFromTerminal >= 0 && orderedVehicleFromTerminal < __instance.itemSalesPercentages.Length)
					{
						float num = (float)__instance.itemSalesPercentages[orderedVehicleFromTerminal] / 100f;
						int creditsWorth = __instance.buyableVehicles[orderedVehicleFromTerminal].creditsWorth;
						int num2 = (int)Math.Round((float)creditsWorth * num);
						saveData.BalanceSpent += num2;
						saveData.lastFullBalance = __instance.groupCredits;
					}
					SaveDataToFile(saveData);
				}
			}
			catch (Exception arg)
			{
				Plugin.Instance.SendLog($"Failed to save purchases on host in BuyItemsServerRpc: {arg}");
			}
		}

		[HarmonyPatch(typeof(Terminal), "TextPostProcess")]
		[HarmonyPrefix]
		private static bool TextPostProcess_Prefix(string modifiedDisplayText, TerminalNode node, ref string __result, Terminal __instance)
		{
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsHost)
			{
				return true;
			}
			if (string.IsNullOrEmpty(modifiedDisplayText) || !modifiedDisplayText.Contains("[numberOfItemsOnRoute]"))
			{
				return true;
			}
			string text;
			if (__instance.vehicleInDropship)
			{
				text = "1 purchased items on route:\n- Cruiser";
			}
			else if (__instance.numberOfItemsInDropship <= 0)
			{
				text = "";
			}
			else
			{
				text = $"{__instance.numberOfItemsInDropship} purchased items on route:";
				foreach (int item in __instance.orderedItemsFromTerminal)
				{
					if (item >= 0 && item < __instance.buyableItemsList.Length)
					{
						text = text + "\n- " + __instance.buyableItemsList[item].itemName;
					}
				}
			}
			__result = modifiedDisplayText.Replace("[numberOfItemsOnRoute]", text);
			return false;
		}

		[HarmonyPatch(typeof(ItemDropship), "FinishDeliveringVehicleClientRpc")]
		[HarmonyPostfix]
		public static void FinishDeliveringVehicleClientRpc(ItemDropship __instance)
		{
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsHost)
			{
				return;
			}
			try
			{
				string saveFilePath = GetSaveFilePath();
				if (File.Exists(saveFilePath))
				{
					File.Delete(saveFilePath);
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance.SendLog(ex.ToString());
			}
		}

		[HarmonyPatch(typeof(ItemDropship), "LandShipClientRpc")]
		[HarmonyPostfix]
		public static void ShipLeavePatch(ItemDropship __instance)
		{
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsHost)
			{
				return;
			}
			try
			{
				string saveFilePath = GetSaveFilePath();
				if (File.Exists(saveFilePath))
				{
					File.Delete(saveFilePath);
				}
			}
			catch (Exception ex)
			{
				Plugin.Instance.SendLog(ex.ToString());
			}
		}

		private static void SaveDataToFile(SaveData data)
		{
			try
			{
				if (!Directory.Exists(SavePath))
				{
					Directory.CreateDirectory(SavePath);
				}
				if (data.OrderedItems.Count > 12)
				{
					int num = data.OrderedItems.Count - 12;
					data.OrderedItems.RemoveRange(data.OrderedItems.Count - num, num);
				}
				string input = JsonUtility.ToJson((object)data);
				string contents = EncryptString(input);
				File.WriteAllText(GetSaveFilePath(), contents);
			}
			catch (Exception arg)
			{
				Plugin.Instance.SendLog($"Failed to save ordered items: {arg}");
			}
		}

		private static SaveData LoadSaveData()
		{
			try
			{
				string saveFilePath = GetSaveFilePath();
				if (!File.Exists(saveFilePath))
				{
					return new SaveData();
				}
				string input = File.ReadAllText(saveFilePath);
				string text = DecryptString(input);
				return JsonUtility.FromJson<SaveData>(text);
			}
			catch (Exception arg)
			{
				Plugin.Instance.SendLog($"Failed to load ordered items: {arg}");
				return new SaveData();
			}
		}

		private static string GetSaveFilePath()
		{
			return Path.Combine(SavePath, GameNetworkManager.Instance.currentSaveFileName + "_ordItems.data");
		}

		private static string EncryptString(string input)
		{
			byte[] bytes = Encoding.UTF8.GetBytes(input);
			for (int i = 0; i < bytes.Length; i++)
			{
				bytes[i] ^= EncKey[i % EncKey.Length];
			}
			return Convert.ToBase64String(bytes);
		}

		private static string DecryptString(string input)
		{
			byte[] array = Convert.FromBase64String(input);
			for (int i = 0; i < array.Length; i++)
			{
				array[i] ^= EncKey[i % EncKey.Length];
			}
			return Encoding.UTF8.GetString(array);
		}
	}
	[BepInPlugin("DropshipItemRecovery", "DropshipItemRecovery", "1.0.3")]
	public class Plugin : BaseUnityPlugin
	{
		public static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			Instance = this;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"DropshipItemRecovery is successfully loaded!");
			try
			{
				Harmony val = new Harmony("DropshipItemRecovery");
				Harmony.CreateAndPatchAll(typeof(BuyItemsServerRpcPatch), (string)null);
				val.PatchAll();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Patches patched!");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		public void SendLog(string text)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)(text ?? ""));
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "DropshipItemRecovery";

		public const string PLUGIN_NAME = "DropshipItemRecovery";

		public const string PLUGIN_VERSION = "1.0.3";
	}
}