Decompiled source of SaveOurLoot v1.5.1

SaveOurLoot.dll

Decompiled a week ago
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.1.0")]
[assembly: AssemblyInformationalVersion("1.5.1+85949613a2c3422324355d344ca4cb6c4c5e2f4d")]
[assembly: AssemblyProduct("SaveOurLoot")]
[assembly: AssemblyTitle("SaveOurLoot")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.1.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<float> saveAllChance;

		public static ConfigEntry<float> saveEachChance;

		public static ConfigEntry<int> scrapLossMax;

		public static ConfigEntry<bool> valueSaveEnabled;

		public static ConfigEntry<float> valueSavePercent;

		public static ConfigEntry<bool> equipmentLossEnabled;

		public static ConfigEntry<float> equipmentLossChance;

		public static ConfigEntry<int> equipmentLossMax;

		public static ConfigEntry<bool> hoardingBugInfestationEnabled;

		public static ConfigEntry<float> hoardingBugInfestationChance;

		public static ConfigEntry<float> hoardingBugInfestationLossEachChance;

		public static ConfigEntry<int> hoardingBugInfestationLossMax;

		public static ConfigEntry<bool> hoardingBugInfestationValueLossEnabled;

		public static ConfigEntry<float> hoardingBugInfestationValueLossPercent;

		public static ConfigEntry<bool> hoardingBugInfestationEquipmentLossEnabled;

		public static ConfigEntry<float> hoardingBugInfestationEquipmentLossChance;

		public static ConfigEntry<int> hoardingBugInfestationEquipmentLossMax;

		public static void Load()
		{
			saveAllChance = Plugin.config.Bind<float>("LootSaving", "SaveAllChance", 0.25f, "A chance of all item being saved.\nVanilla value 0. Values between 0-1.");
			saveEachChance = Plugin.config.Bind<float>("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<int>("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<bool>("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<float>("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<bool>("EquipmentLoss", "EquipmentLossEnabled", false, "Will it allow equipment to be lost?\nVanilla value False.");
			equipmentLossChance = Plugin.config.Bind<float>("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<int>("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<bool>("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<float>("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<float>("HoardingBugInfestation", "HoardingBugInfestationLossEachChance", 0.1f, "A chance of each item being stolen by Hoarding Bugs.\nValues between 0-1.");
			hoardingBugInfestationLossMax = Plugin.config.Bind<int>("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<bool>("HoardingBugInfestation", "HoardingBugInfestationValueLossEnabled", true, "Will it try to steal items based on it scrap value?\nPrevent HoardingBugInfestationLossEachChance\nVanilla value False.");
			hoardingBugInfestationValueLossPercent = Plugin.config.Bind<float>("HoardingBugInfestation", "HoardingBugInfestationValueLossPercent", 0.1f, "What percentage of total scrap value will be stolen among loot.\nValues between 0-1.");
			hoardingBugInfestationEquipmentLossEnabled = Plugin.config.Bind<bool>("HoardingBugInfestation", "HoardingBugInfestationEquipmentLossEnabled", true, "Will it allow stealing of equipment?");
			hoardingBugInfestationEquipmentLossChance = Plugin.config.Bind<float>("HoardingBugInfestation", "HoardingBugInfestationEquipmentLossChance", 0.05f, "A chance of each equipment being stollen.\nValues between 0-1.");
			hoardingBugInfestationEquipmentLossMax = Plugin.config.Bind<int>("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<CodeInstruction> RM_DespawnPropsAtEndOfRound_Transpiler(IEnumerable<CodeInstruction> 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<CodeInstruction> list = new List<CodeInstruction>(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<CodeInstruction> list2 = new List<CodeInstruction>();
				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<GrabbableObject> list = new List<GrabbableObject>();
			try
			{
				VehicleController[] array = Object.FindObjectsByType<VehicleController>((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<BeltBagItem>((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<bool, GrabbableObject> lookup = list.ToLookup((GrabbableObject go) => go.itemProperties.isScrap);
			List<GrabbableObject> list2 = lookup[true].ToList();
			List<GrabbableObject> list3 = lookup[false].ToList();
			ConfigEntry<bool> hoardingBugInfestationEnabled = Config.hoardingBugInfestationEnabled;
			if (hoardingBugInfestationEnabled != null && hoardingBugInfestationEnabled.Value && random.NextDouble() >= (double)(1f - (Config.hoardingBugInfestationChance?.Value ?? 1f)))
			{
				List<string> list4 = new List<string>();
				ConfigEntry<bool> 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<bool> 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<string> list5 = new List<string>();
					ConfigEntry<bool> 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<bool> 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)
			{
				if (gObject.isHeld && (Object)(object)gObject.playerHeldBy != (Object)null)
				{
					gObject.playerHeldBy.DropAllHeldItems(true, false);
				}
				((Component)gObject).gameObject.GetComponent<NetworkObject>().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.1")]
	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.1";
	}
}