using System;
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.4.0.0")]
[assembly: AssemblyInformationalVersion("1.4.0+979f2849e735ed3c95064b823298eff3402ad5be")]
[assembly: AssemblyProduct("SaveOurLoot")]
[assembly: AssemblyTitle("SaveOurLoot")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.4.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 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>();
foreach (GrabbableObject val in gObjects)
{
if ((!val.isInShipRoom && !val.isHeld) || val.deactivated)
{
Plugin.MLogS.LogInfo((object)(((Object)val).name + " Lost Outside"));
DespawnItem(val);
}
else
{
list.Add(val);
}
}
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)))
{
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}");
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"));
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"));
DespawnItem(item3);
num4++;
if (num4 >= (Config.hoardingBugInfestationEquipmentLossMax?.Value ?? int.MaxValue))
{
Plugin.MLogS.LogInfo((object)$"Equipment Lost Mafia total {num4}");
break;
}
}
}
}
}
if (StartOfRound.Instance.allPlayersDead)
{
if (random.NextDouble() >= (double)(1f - (Config.saveAllChance?.Value ?? 0.25f)))
{
Plugin.MLogS.LogInfo((object)"All Saved");
}
else
{
list2.RemoveAll((GrabbableObject go) => !((NetworkBehaviour)go).IsSpawned);
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}");
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"));
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"));
DespawnItem(item6);
num8++;
if (num8 >= (Config.equipmentLossMax?.Value ?? int.MaxValue))
{
Plugin.MLogS.LogInfo((object)$"Equipment Lost total {num8}");
break;
}
}
}
}
}
}
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);
}
}
}
}
[BepInPlugin("MrHydralisk.SaveOurLoot", "Save Our Loot", "1.4.0")]
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.4.0";
}
}