Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DropshipItemRecovery v1.0.3
DropshipItemRecovery.dll
Decompiled 11 months agousing 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"; } }