using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SaveOurLoot")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Mod for Lethal Company, that allow adjusting item loss after mission")] [assembly: AssemblyFileVersion("1.5.4.0")] [assembly: AssemblyInformationalVersion("1.5.4+bd05993215a3691593cd676fd0ecee2d428b05da")] [assembly: AssemblyProduct("SaveOurLoot")] [assembly: AssemblyTitle("SaveOurLoot")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.5.4.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 SaveOurLoot { public class Config { public static ConfigEntry saveAllChance; public static ConfigEntry saveEachChance; public static ConfigEntry scrapLossMax; public static ConfigEntry valueSaveEnabled; public static ConfigEntry valueSavePercent; public static ConfigEntry equipmentLossEnabled; public static ConfigEntry equipmentLossChance; public static ConfigEntry equipmentLossMax; public static ConfigEntry hoardingBugInfestationEnabled; public static ConfigEntry hoardingBugInfestationChance; public static ConfigEntry hoardingBugInfestationLossEachChance; public static ConfigEntry hoardingBugInfestationLossMax; public static ConfigEntry hoardingBugInfestationValueLossEnabled; public static ConfigEntry hoardingBugInfestationValueLossPercent; public static ConfigEntry hoardingBugInfestationEquipmentLossEnabled; public static ConfigEntry hoardingBugInfestationEquipmentLossChance; public static ConfigEntry hoardingBugInfestationEquipmentLossMax; public static void Load() { saveAllChance = Plugin.config.Bind("LootSaving", "SaveAllChance", 0.25f, "A chance of all item being saved.\nVanilla value 0. Values between 0-1."); saveEachChance = Plugin.config.Bind("LootSaving", "SaveEachChance", 0.5f, "A chance of each item being saved.\nApplied after SaveAllChance\nVanilla value 0. Values between 0-1."); scrapLossMax = Plugin.config.Bind("LootSaving", "ScrapLossMax", int.MaxValue, $"The maximum amount of items that can be lost.\nApplied after SaveEachChance\nVanilla value {int.MaxValue}. Values between 0-{int.MaxValue}."); valueSaveEnabled = Plugin.config.Bind("LootSaving", "ValueSaveEnabled", false, "Will it try to save item based on it scrap value?\nApplied after SaveAllChance and prevent SaveEachChance\nVanilla value False."); valueSavePercent = Plugin.config.Bind("LootSaving", "ValueSavePercent", 0.25f, "What percentage of total scrap value will be saved among loot.\nVanilla value 0. Values between 0-1."); equipmentLossEnabled = Plugin.config.Bind("EquipmentLoss", "EquipmentLossEnabled", false, "Will it allow equipment to be lost?\nVanilla value False."); equipmentLossChance = Plugin.config.Bind("EquipmentLoss", "EquipmentLossChance", 0.1f, "A chance of each equipment being lost.\nApplied after SaveAllChance\nVanilla value 0. Values between 0-1."); equipmentLossMax = Plugin.config.Bind("EquipmentLoss", "EquipmentLossMax", int.MaxValue, $"The maximum amount of equipment that can be lost.\nApplied after EquipmentLossChance\nVanilla value 0. Values between 0-{int.MaxValue}."); hoardingBugInfestationEnabled = Plugin.config.Bind("HoardingBugInfestation", "HoardingBugInfestationEnabled", false, "Space is a dangerous place. Bug Mafia will protect you for a little part of your loot.\nYour Ship is infested with Hoarding Bugs, which steal your loot while you sleep between missions.\nEnable all features related to this category?\nVanilla value False."); hoardingBugInfestationChance = Plugin.config.Bind("HoardingBugInfestation", "HoardingBugInfestationChance", 1f, "A chance of items being stolen by Hoarding Bugs each night on the Ship.\nValues between 0-1."); hoardingBugInfestationLossEachChance = Plugin.config.Bind("HoardingBugInfestation", "HoardingBugInfestationLossEachChance", 0.1f, "A chance of each item being stolen by Hoarding Bugs.\nValues between 0-1."); hoardingBugInfestationLossMax = Plugin.config.Bind("HoardingBugInfestation", "HoardingBugInfestationLossMax", int.MaxValue, $"The maximum amount of items that can be lost.\nApplied after HoardingBugInfestationLossEachChance\nVanilla value {int.MaxValue}. Values between 0-{int.MaxValue}."); hoardingBugInfestationValueLossEnabled = Plugin.config.Bind("HoardingBugInfestation", "HoardingBugInfestationValueLossEnabled", true, "Will it try to steal items based on it scrap value?\nPrevent HoardingBugInfestationLossEachChance\nVanilla value False."); hoardingBugInfestationValueLossPercent = Plugin.config.Bind("HoardingBugInfestation", "HoardingBugInfestationValueLossPercent", 0.1f, "What percentage of total scrap value will be stolen among loot.\nValues between 0-1."); hoardingBugInfestationEquipmentLossEnabled = Plugin.config.Bind("HoardingBugInfestation", "HoardingBugInfestationEquipmentLossEnabled", true, "Will it allow stealing of equipment?"); hoardingBugInfestationEquipmentLossChance = Plugin.config.Bind("HoardingBugInfestation", "HoardingBugInfestationEquipmentLossChance", 0.05f, "A chance of each equipment being stollen.\nValues between 0-1."); hoardingBugInfestationEquipmentLossMax = Plugin.config.Bind("HoardingBugInfestation", "HoardingBugInfestationEquipmentLossMax", int.MaxValue, $"The maximum amount of equipment that can be stollen.\nApplied after EquipmentLossChance\nValues between 0-{int.MaxValue}."); } } public class HarmonyPatches { private static readonly Type patchType; static HarmonyPatches() { //IL_0014: 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) //IL_0048: Expected O, but got Unknown patchType = typeof(HarmonyPatches); new Harmony("LethalCompany.MrHydralisk.SaveOurLoot").Patch((MethodBase)AccessTools.Method(typeof(RoundManager), "DespawnPropsAtEndOfRound", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(patchType, "RM_DespawnPropsAtEndOfRound_Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } public static IEnumerable RM_DespawnPropsAtEndOfRound_Transpiler(IEnumerable instructions, ILGenerator il) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown int num = -1; int num2 = -1; List list = new List(instructions); for (int i = 0; i < list.Count; i++) { if (!(list[i].opcode == OpCodes.Stloc_0)) { continue; } num = i; for (int j = num + 1; j < list.Count; j++) { if (CodeInstructionExtensions.Is(list[j], OpCodes.Ldstr, (object)"TemporaryEffect")) { num2 = j; break; } } if (num2 > -1) { break; } } if (num > -1 && num2 > -1) { Label label = il.DefineLabel(); list[num2].labels.Add(label); List list2 = new List(); list2.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list2.Add(new CodeInstruction(OpCodes.Ldloc_0, (object)null)); list2.Add(new CodeInstruction(OpCodes.Ldarg_1, (object)null)); list2.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(HarmonyPatches), "CustomDespawnProps", (Type[])null, (Type[])null))); list2.Add(new CodeInstruction(OpCodes.Brtrue_S, (object)label)); list.InsertRange(num + 1, list2); } return list.AsEnumerable(); } public static bool CustomDespawnProps(RoundManager rManager, GrabbableObject[] gObjects, bool despawnAllItems = false) { if (despawnAllItems) { return false; } Random random = new Random(StartOfRound.Instance.randomMapSeed + 369); gObjects.ToList(); List list = new List(); try { VehicleController[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (VehicleController val in array) { if (!val.magnetedToShip) { if ((Object)(object)((NetworkBehaviour)val).NetworkObject != (Object)null) { Debug.Log((object)"Despawn vehicle"); ((NetworkBehaviour)val).NetworkObject.Despawn(false); } } else { val.CollectItemsInTruck(); } } } catch (Exception arg) { Debug.LogError((object)$"Error despawning vehicle: {arg}"); } BeltBagItem[] array2 = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (BeltBagItem val2 in array2) { if (Object.op_Implicit((Object)(object)val2.insideAnotherBeltBag) && (((GrabbableObject)val2.insideAnotherBeltBag).isInShipRoom || ((GrabbableObject)val2.insideAnotherBeltBag).isHeld)) { ((GrabbableObject)val2).isInElevator = true; ((GrabbableObject)val2).isInShipRoom = true; } if (((GrabbableObject)val2).isInShipRoom || ((GrabbableObject)val2).isHeld) { for (int k = 0; k < val2.objectsInBag.Count; k++) { val2.objectsInBag[k].isInElevator = true; val2.objectsInBag[k].isInShipRoom = true; } } } foreach (GrabbableObject val3 in gObjects) { if (!((Object)(object)val3 == (Object)null)) { if ((!val3.isInShipRoom && !val3.isHeld) || val3.deactivated) { Plugin.MLogS.LogInfo((object)(((Object)val3).name + " Lost Outside")); DespawnItem(val3); } else { list.Add(val3); } } } ILookup lookup = list.ToLookup((GrabbableObject go) => go.itemProperties.isScrap); List list2 = lookup[true].ToList(); List list3 = lookup[false].ToList(); ConfigEntry hoardingBugInfestationEnabled = Config.hoardingBugInfestationEnabled; if (hoardingBugInfestationEnabled != null && hoardingBugInfestationEnabled.Value && random.NextDouble() >= (double)(1f - (Config.hoardingBugInfestationChance?.Value ?? 1f))) { List list4 = new List(); ConfigEntry hoardingBugInfestationValueLossEnabled = Config.hoardingBugInfestationValueLossEnabled; if (hoardingBugInfestationValueLossEnabled != null && hoardingBugInfestationValueLossEnabled.Value) { list2 = list2.OrderByDescending((GrabbableObject go) => go.scrapValue).ToList(); float num = (float)list2.Sum((GrabbableObject go) => go.scrapValue) * (Config.hoardingBugInfestationValueLossPercent?.Value ?? 0.1f); int num2 = 0; foreach (GrabbableObject item in list2) { num2 += item.scrapValue; Plugin.MLogS.LogInfo((object)$"{((Object)item).name} Lost Value Mafia {item.scrapValue}"); list4.Add(item.itemProperties?.itemName ?? ((Object)item).name); DespawnItem(item); if ((float)num2 >= num) { Plugin.MLogS.LogInfo((object)$"{num2} Scrap Value Lost Mafia"); break; } } } else { int num3 = 0; foreach (GrabbableObject item2 in list2) { if (random.NextDouble() >= (double)(1f - (Config.hoardingBugInfestationLossEachChance?.Value ?? 0.1f))) { Plugin.MLogS.LogInfo((object)(((Object)item2).name + " Lost Mafia")); list4.Add(item2.itemProperties?.itemName ?? ((Object)item2).name); DespawnItem(item2); num3++; if (num3 >= (Config.hoardingBugInfestationLossMax?.Value ?? int.MaxValue)) { Plugin.MLogS.LogInfo((object)$"Lost Mafia total {num3}"); break; } } } } ConfigEntry hoardingBugInfestationEquipmentLossEnabled = Config.hoardingBugInfestationEquipmentLossEnabled; if (hoardingBugInfestationEquipmentLossEnabled != null && hoardingBugInfestationEquipmentLossEnabled.Value) { int num4 = 0; foreach (GrabbableObject item3 in list3) { if (random.NextDouble() >= (double)(1f - (Config.hoardingBugInfestationEquipmentLossChance?.Value ?? 0.05f))) { Plugin.MLogS.LogInfo((object)(((Object)item3).name + " Equipment Lost Mafia")); list4.Add(item3.itemProperties?.itemName ?? ((Object)item3).name); DespawnItem(item3); num4++; if (num4 >= (Config.hoardingBugInfestationEquipmentLossMax?.Value ?? int.MaxValue)) { Plugin.MLogS.LogInfo((object)$"Equipment Lost Mafia total {num4}"); break; } } } } if (list4.Count() > 0) { string text = $"Lost to Bug Mafia ({list4.Count()}/{list.Count()}): "; text += string.Join("; ", from s in list4 group s by s into s select new { name = s.Key, count = s.Count() } into item select (item.count <= 1) ? item.name : $"{item.name} x{item.count}"); ((MonoBehaviour)HUDManager.Instance).StartCoroutine(DisplayAlert("Bug Mafia", "Space ain't no picnic, see? We kept you safe out there, so a little somethin' for our troubles, understand?", text)); } } if (StartOfRound.Instance.allPlayersDead) { if (random.NextDouble() >= (double)(1f - (Config.saveAllChance?.Value ?? 0.25f))) { Plugin.MLogS.LogInfo((object)"All Saved"); ((MonoBehaviour)HUDManager.Instance).StartCoroutine(DisplayAlert("Save Our Loot", "You got lucky. All items was saved.", "You got lucky. All items was saved.")); } else { list2.RemoveAll((GrabbableObject go) => !((NetworkBehaviour)go).IsSpawned); List list5 = new List(); ConfigEntry valueSaveEnabled = Config.valueSaveEnabled; if (valueSaveEnabled != null && valueSaveEnabled.Value) { list2 = list2.OrderByDescending((GrabbableObject go) => go.scrapValue).ToList(); int num5 = list2.Sum((GrabbableObject go) => go.scrapValue); float num6 = (float)num5 * (Config.valueSavePercent?.Value ?? 0.25f); foreach (GrabbableObject item4 in list2) { num5 -= item4.scrapValue; Plugin.MLogS.LogInfo((object)$"{((Object)item4).name} Lost Value {item4.scrapValue}"); list5.Add(item4.itemProperties?.itemName ?? ((Object)item4).name); DespawnItem(item4); if ((float)num5 < num6) { Plugin.MLogS.LogInfo((object)$"{num5} Scrap Value Saved"); break; } } } else { int num7 = 0; foreach (GrabbableObject item5 in list2) { if (random.NextDouble() >= (double)(1f - (Config.saveEachChance?.Value ?? 0.5f))) { Plugin.MLogS.LogInfo((object)(((Object)item5).name + " Saved")); continue; } Plugin.MLogS.LogInfo((object)(((Object)item5).name + " Lost")); list5.Add(item5.itemProperties?.itemName ?? ((Object)item5).name); DespawnItem(item5); num7++; if (num7 < (Config.scrapLossMax?.Value ?? int.MaxValue)) { continue; } Plugin.MLogS.LogInfo((object)$"Lost total {num7}"); break; } } ConfigEntry equipmentLossEnabled = Config.equipmentLossEnabled; if (equipmentLossEnabled != null && equipmentLossEnabled.Value) { list3.RemoveAll((GrabbableObject go) => !((NetworkBehaviour)go).IsSpawned); int num8 = 0; foreach (GrabbableObject item6 in list3) { if (random.NextDouble() >= (double)(1f - (Config.equipmentLossChance?.Value ?? 0.1f))) { Plugin.MLogS.LogInfo((object)(((Object)item6).name + " Equipment Lost")); list5.Add(item6.itemProperties?.itemName ?? ((Object)item6).name); DespawnItem(item6); num8++; if (num8 >= (Config.equipmentLossMax?.Value ?? int.MaxValue)) { Plugin.MLogS.LogInfo((object)$"Equipment Lost total {num8}"); break; } } } } if (list5.Count() > 0) { string text2 = $"Lost items ({list5.Count()}/{list.Count()}): "; text2 += string.Join("; ", from s in list5 group s by s into s select new { name = s.Key, count = s.Count() } into item select (item.count <= 1) ? item.name : $"{item.name} x{item.count}"); ((MonoBehaviour)HUDManager.Instance).StartCoroutine(DisplayAlert("Save Our Loot", "Some of your loot was lost.", text2)); } } } return true; void DespawnItem(GrabbableObject gObject) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) if (gObject.isHeld && (Object)(object)gObject.playerHeldBy != (Object)null) { gObject.playerHeldBy.DropAllHeldItems(true, false, false, false, default(Vector3), default(Vector3), default(Vector3), default(Vector3), default(Vector3)); } ((Component)gObject).gameObject.GetComponent().Despawn(true); if (rManager.spawnedSyncedObjects.Contains(((Component)gObject).gameObject)) { rManager.spawnedSyncedObjects.Remove(((Component)gObject).gameObject); } } static IEnumerator DisplayAlert(string headerAlertText = "Save Our Loot", string bodyAlertText = "", string messageText = "") { int index = 0; while (index < 20 && !StartOfRound.Instance.inShipPhase) { index++; yield return (object)new WaitForSeconds(5f); } yield return (object)new WaitForSeconds(2f); if (!string.IsNullOrEmpty(headerAlertText) || !string.IsNullOrEmpty(bodyAlertText)) { HUDManager.Instance.DisplayTip(headerAlertText, bodyAlertText, false, false, "LC_Tip1"); } if (!string.IsNullOrEmpty(messageText)) { HUDManager.Instance.AddTextToChatOnServer(messageText, -1); } } } } [BepInPlugin("MrHydralisk.SaveOurLoot", "Save Our Loot", "1.5.4")] public class Plugin : BaseUnityPlugin { private const string MOD_GUID = "MrHydralisk.SaveOurLoot"; private const string MOD_NAME = "Save Our Loot"; public static Plugin instance; public static ManualLogSource MLogS; public static ConfigFile config; private void Awake() { MLogS = Logger.CreateLogSource("MrHydralisk.SaveOurLoot"); config = ((BaseUnityPlugin)this).Config; Config.Load(); instance = this; try { RuntimeHelpers.RunClassConstructor(typeof(HarmonyPatches).TypeHandle); } catch (Exception ex) { MLogS.LogError((object)string.Concat("Error in static constructor of ", typeof(HarmonyPatches), ": ", ex)); } MLogS.LogInfo((object)"Plugin is loaded!"); } } public static class PluginInfo { public const string PLUGIN_GUID = "SaveOurLoot"; public const string PLUGIN_NAME = "SaveOurLoot"; public const string PLUGIN_VERSION = "1.5.4"; } }