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 ScrapLossBalancer v1.0.0
BepInEx/plugins/AscendTV.LethalCompany.ScrapLossBalancer.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using AscendTV.LethalCompany.ScrapLossBalancer.Patches; 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: AssemblyCompany("AscendTV.LethalCompany.ScrapLossBalancer")] [assembly: AssemblyProduct("AscendTV.LethalCompany.ScrapLossBalancer")] [assembly: AssemblyTitle("AscendTV.LethalCompany.ScrapLossBalancer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("1.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace AscendTV.LethalCompany.ScrapLossBalancer { public static class Configuration { private static ConfigEntry<float>? _penaltyScrapPercent; private static ConfigEntry<ScrapCalculationType>? _scrapCalculationType; private static ConfigEntry<bool>? _modEnabled; public static float PenaltyScrapPercent => _penaltyScrapPercent?.Value ?? 12.5f; public static ScrapCalculationType ScrapCalculationType => _scrapCalculationType?.Value ?? ScrapCalculationType.PerPlayer; public static bool ModEnabled => _modEnabled?.Value ?? false; public static void Setup(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown _modEnabled = config.Bind<bool>("General", "Enabled", true, "Enables the mod. When enabled, reduces scrap loss when all players die.\r\n\r\nNo restart required. Host only."); _penaltyScrapPercent = config.Bind<float>("General", "Scrap Penalty (%)", 12.5f, new ConfigDescription("Percent of scrap value to remove from the ship when all players die.\r\n\r\nExample: If you had 2000 scrap on ship with 3 players, 25% per player, death would result in around 500 scrap remaining.\r\n\r\nNo restart required. Takes effect on next full wipe.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); _scrapCalculationType = config.Bind<ScrapCalculationType>("General", "Calculation Type", ScrapCalculationType.PerPlayer, "Describes how the penalty is calculated, either per player or as a static value.\r\nValid options: PerPlayer, TotalPercent\r\n\r\nNo restart required. Takes effect on next full wipe."); } } public class PluginInfo { public const string GUID = "ascendtv.lethal.ScrapLossBalancer"; public const string Name = "Scrap Loss Balancer"; public const string ShortVersion = "1.0.0"; public const string Version = "1.0.0.0"; public const string ShortName = "ScrapLossBalancer"; public const string Description = "Change team death to lose a percentage of scrap, scaled by number of players."; } public enum ScrapCalculationType { [Description("Per Player")] PerPlayer, [Description("Total Percent")] TotalPercent } [BepInPlugin("ascendtv.lethal.ScrapLossBalancer", "Scrap Loss Balancer", "1.0.0.0")] public class ScrapLossBalancerModBase : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("ascendtv.lethal.ScrapLossBalancer"); internal static ManualLogSource? Log; private void Awake() { Configuration.Setup(((BaseUnityPlugin)this).Config); Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)("Scrap Loss Balancer loaded. " + $"Penalty: {Configuration.PenaltyScrapPercent:0.##}% " + $"{Configuration.ScrapCalculationType}")); _harmony.PatchAll(typeof(ScrapLossBalancerModBase)); _harmony.PatchAll(typeof(RoundManagerPatch)); } } } namespace AscendTV.LethalCompany.ScrapLossBalancer.Patches { [HarmonyPatch(typeof(RoundManager))] public class RoundManagerPatch { [HarmonyPatch(typeof(RoundManager), "DespawnPropsAtEndOfRound")] [HarmonyPrefix] [HarmonyPriority(200)] public static void DespawnPropsAtEndOfRoundPre(out bool __state) { if (!((NetworkBehaviour)RoundManager.Instance).IsServer || !Configuration.ModEnabled) { __state = false; return; } __state = StartOfRound.Instance.allPlayersDead; StartOfRound.Instance.allPlayersDead = false; } [HarmonyPatch(typeof(RoundManager), "DespawnPropsAtEndOfRound")] [HarmonyPostfix] [HarmonyPriority(600)] public static void DespawnPropsAtEndOfRoundPost(bool __state) { if (!((NetworkBehaviour)RoundManager.Instance).IsServer || !Configuration.ModEnabled) { return; } bool flag = __state; StartOfRound.Instance.allPlayersDead = flag; if (!flag) { return; } List<GrabbableObject> list = (from s in GameObject.Find("/Environment/HangarShip").GetComponentsInChildren<GrabbableObject>() where s.itemProperties.isScrap select s).ToList(); int num = list.Sum((GrabbableObject s) => s.scrapValue); float num2 = CalculateTargetScrapPercent(); ManualLogSource? log = ScrapLossBalancerModBase.Log; if (log != null) { log.LogInfo((object)$"Attempting to remove {num2 * 100f}% scrap value from {list.Count} scrap items."); } Math.Round((float)num * num2); foreach (GrabbableObject item in GetScrapAtLeastTargetPercent(list, num2)) { DespawnObject(item); } } private static float CalculateTargetScrapPercent() { if (Configuration.ScrapCalculationType == ScrapCalculationType.PerPlayer) { return Math.Clamp((float)(StartOfRound.Instance.connectedPlayersAmount + 1) * Configuration.PenaltyScrapPercent / 100f, 0f, 1f); } return Math.Clamp(Configuration.PenaltyScrapPercent / 100f, 0f, 1f); } private static void DespawnObject(GrabbableObject item) { item.scrapPersistedThroughRounds = false; NetworkObject component = ((Component)item).gameObject.GetComponent<NetworkObject>(); if ((Object)(object)component != (Object)null && component.IsSpawned) { ((Component)item).gameObject.GetComponent<NetworkObject>().Despawn(true); } else { Object.Destroy((Object)(object)((Component)item).gameObject); } ManualLogSource? log = ScrapLossBalancerModBase.Log; if (log != null) { log.LogDebug((object)$"Item Destroyed: {((Object)item).name}, Value: {item.scrapValue}"); } } private static List<GrabbableObject> GetScrapAtLeastTargetPercent(List<GrabbableObject> allScrap, double targetPercent) { if (allScrap.Count < 2 || targetPercent >= 100.0) { return allScrap; } int num = (int)((double)allScrap.Sum((GrabbableObject item) => item.scrapValue) * targetPercent); List<GrabbableObject> list = new List<GrabbableObject>(); int num2 = 0; foreach (GrabbableObject item in allScrap.OrderByDescending((GrabbableObject item) => item.scrapValue)) { if (num2 + item.scrapValue > num) { break; } list.Add(item); num2 += item.scrapValue; } foreach (GrabbableObject item2 in allScrap.OrderBy((GrabbableObject item) => item.scrapValue)) { if (num2 >= num) { break; } list.Add(item2); num2 += item2.scrapValue; } ManualLogSource? log = ScrapLossBalancerModBase.Log; if (log != null) { log.LogInfo((object)$"Removing {list.Count} items for penalty. Target value: {num}, Actual: {num2}"); } return list; } } }