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 WeeWeeShotgunTweaks v1.0.4
BepInEx/plugins/WeeWeeShotgunTweaks/WeeWeeShotgunTweaks.dll
Decompiled 3 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("WeeWeeShotgunTweaks")] [assembly: AssemblyDescription("Lethal Company shotgun and friendly-fire tweaks")] [assembly: AssemblyCompany("WeeWee")] [assembly: AssemblyProduct("WeeWeeShotgunTweaks")] [assembly: AssemblyFileVersion("1.0.4.0")] [assembly: AssemblyVersion("1.0.4.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 WeeWeeShotgunTweaks { [BepInPlugin("LilWeeWee.WeeWeeShotgunTweaks", "Wee Wee Shotgun Tweaks", "1.0.4")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "LilWeeWee.WeeWeeShotgunTweaks"; public const string PluginName = "Wee Wee Shotgun Tweaks"; public const string PluginVersion = "1.0.4"; internal static ModConfig Settings { get; private set; } private void Awake() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) Settings = new ModConfig(((BaseUnityPlugin)this).Config); new Harmony("LilWeeWee.WeeWeeShotgunTweaks").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Wee Wee Shotgun Tweaks 1.0.4 loaded."); } private void Update() { TemporaryRootClear.Tick(); } } internal sealed class ModConfig { internal ConfigEntry<bool> InfiniteShotgunAmmo { get; } internal ConfigEntry<bool> DisableShotgunMisfire { get; } internal ConfigEntry<bool> DisableIncomingFriendlyFire { get; } internal ConfigEntry<bool> DisableOutgoingFriendlyFire { get; } internal ConfigEntry<int> ShotgunDamage { get; } internal ConfigEntry<int> ShovelDamage { get; } internal ConfigEntry<bool> ClearCadaverRoots { get; } internal ConfigEntry<float> RootClearDuration { get; } internal ConfigEntry<bool> ClearSpiderWebs { get; } internal ConfigEntry<float> SpiderWebClearRange { get; } internal ConfigEntry<float> SpiderWebClearAngle { get; } internal ModConfig(ConfigFile config) { InfiniteShotgunAmmo = config.Bind<bool>("Shotgun", "InfiniteShotgunAmmo", true, "Prevents player-held shotguns from consuming shells."); DisableShotgunMisfire = config.Bind<bool>("Shotgun", "DisableShotgunMisfire", true, "Prevents dropped player shotguns from firing by themselves."); ShotgunDamage = config.Bind<int>("Shotgun", "ShotgunDamage", -1, "Custom shotgun damage. -1 keeps the game's normal damage value."); DisableIncomingFriendlyFire = config.Bind<bool>("Friendly Fire", "DisableIncomingFriendlyFire", true, "Blocks damage dealt to you by another player."); DisableOutgoingFriendlyFire = config.Bind<bool>("Friendly Fire", "DisableOutgoingFriendlyFire", true, "Blocks your weapon damage against other players."); ShovelDamage = config.Bind<int>("Shovel", "ShovelDamage", 2, "Damage force used by shovels and signs. Vanilla is normally 1."); ClearCadaverRoots = config.Bind<bool>("Cadaver Growth", "TemporarilyClearRoots", true, "Player-fired shotgun blasts temporarily hide Cadaver Growth roots so players can see through them."); RootClearDuration = config.Bind<float>("Cadaver Growth", "RootClearDuration", 5f, "Seconds Cadaver Growth roots stay visually cleared after a player fires a shotgun."); ClearSpiderWebs = config.Bind<bool>("Spider Webs", "ShotgunsClearSpiderWebs", true, "Allows player-fired shotgun blasts to permanently break spider webs in their path."); SpiderWebClearRange = config.Bind<float>("Spider Webs", "SpiderWebClearRange", 15f, "Maximum distance in metres at which a shotgun blast can break spider webs."); SpiderWebClearAngle = config.Bind<float>("Spider Webs", "SpiderWebClearAngle", 70f, "Total forward cone angle in degrees used when detecting spider webs hit by a shotgun blast."); } } internal static class SpiderWebClear { internal static void TryClear(ShotgunItem shotgun, Vector3 shotPosition, Vector3 shotForward) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.Settings.ClearSpiderWebs.Value || (Object)(object)shotgun == (Object)null || ((GrabbableObject)shotgun).isHeldByEnemy) { return; } PlayerControllerB localPlayer = Helpers.LocalPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)((GrabbableObject)shotgun).playerHeldBy != (Object)(object)localPlayer) { return; } float num = Mathf.Clamp(Plugin.Settings.SpiderWebClearRange.Value, 1f, 50f); float num2 = Mathf.Clamp(Plugin.Settings.SpiderWebClearAngle.Value, 5f, 180f) * 0.5f; SandSpiderWebTrap[] array = Object.FindObjectsOfType<SandSpiderWebTrap>(); foreach (SandSpiderWebTrap val in array) { if (!((Object)(object)val == (Object)null) && !val.webHasBeenBroken) { Vector3 val2 = (((Object)(object)val.centerOfWeb != (Object)null) ? val.centerOfWeb.position : ((Component)val).transform.position) - shotPosition; float magnitude = ((Vector3)(ref val2)).magnitude; if (!(magnitude > num) && !(magnitude <= 0.01f) && !(Vector3.Angle(shotForward, val2) > num2)) { val.Hit(1, ((Vector3)(ref val2)).normalized, localPlayer, true, -1); } } } } } internal static class TemporaryRootClear { private static readonly Dictionary<BatchAllMeshChildren, bool> BatchStates = new Dictionary<BatchAllMeshChildren, bool>(); private static readonly Dictionary<MeshRenderer, bool> RendererStates = new Dictionary<MeshRenderer, bool>(); private static float _clearUntil; private static float _nextRefresh; private static bool _active; internal static void Trigger() { if (Plugin.Settings.ClearCadaverRoots.Value) { float num = Mathf.Clamp(Plugin.Settings.RootClearDuration.Value, 0.25f, 60f); _clearUntil = Mathf.Max(_clearUntil, Time.time + num); _active = true; HideCurrentRoots(); } } internal static void Tick() { if (_active) { if (Time.time >= _clearUntil) { RestoreRoots(); } else if (Time.time >= _nextRefresh) { _nextRefresh = Time.time + 0.25f; HideCurrentRoots(); } } } private static void HideCurrentRoots() { CadaverGrowthAI[] array = Object.FindObjectsOfType<CadaverGrowthAI>(); foreach (CadaverGrowthAI val in array) { if ((Object)(object)val == (Object)null) { continue; } if (val.plantBatchers != null) { BatchAllMeshChildren[] plantBatchers = val.plantBatchers; foreach (BatchAllMeshChildren val2 in plantBatchers) { if (!((Object)(object)val2 == (Object)null)) { if (!BatchStates.ContainsKey(val2)) { BatchStates.Add(val2, ((Behaviour)val2).enabled); } ((Behaviour)val2).enabled = false; } } } if (val.GrowthTiles == null) { continue; } foreach (TileWithGrowth growthTile in val.GrowthTiles) { if (growthTile == null || (Object)(object)growthTile.plantsContainer == (Object)null) { continue; } MeshRenderer[] componentsInChildren = growthTile.plantsContainer.GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val3 in componentsInChildren) { if (!((Object)(object)val3 == (Object)null)) { if (!RendererStates.ContainsKey(val3)) { RendererStates.Add(val3, ((Renderer)val3).enabled); } ((Renderer)val3).enabled = false; } } } } } private static void RestoreRoots() { foreach (KeyValuePair<BatchAllMeshChildren, bool> batchState in BatchStates) { if ((Object)(object)batchState.Key != (Object)null) { ((Behaviour)batchState.Key).enabled = batchState.Value; } } foreach (KeyValuePair<MeshRenderer, bool> rendererState in RendererStates) { if ((Object)(object)rendererState.Key != (Object)null) { ((Renderer)rendererState.Key).enabled = rendererState.Value; } } BatchStates.Clear(); RendererStates.Clear(); _active = false; _clearUntil = 0f; _nextRefresh = 0f; } } internal static class Helpers { [ThreadStatic] private static int _enemyShotDepth; internal static PlayerControllerB LocalPlayer { get { if (!((Object)(object)GameNetworkManager.Instance != (Object)null)) { return null; } return GameNetworkManager.Instance.localPlayerController; } } internal static bool EnemyShotInProgress => _enemyShotDepth > 0; internal static void BeginEnemyShot(ShotgunItem shotgun) { if ((Object)(object)shotgun != (Object)null && ((GrabbableObject)shotgun).isHeldByEnemy) { _enemyShotDepth++; } } internal static void EndEnemyShot(ShotgunItem shotgun) { if ((Object)(object)shotgun != (Object)null && ((GrabbableObject)shotgun).isHeldByEnemy && _enemyShotDepth > 0) { _enemyShotDepth--; } } internal static bool IsWeaponCause(CauseOfDeath cause) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)cause != 1) { return (int)cause == 7; } return true; } } [HarmonyPatch(typeof(ShotgunItem), "ShootGun")] internal static class ShotgunShootPatch { [HarmonyPrefix] private static bool PreventDroppedMisfire(ShotgunItem __instance) { Helpers.BeginEnemyShot(__instance); if (!Plugin.Settings.DisableShotgunMisfire.Value) { return true; } if (!((GrabbableObject)__instance).isHeld) { return ((GrabbableObject)__instance).isHeldByEnemy; } return true; } [HarmonyFinalizer] private static void FinishEnemyShot(ShotgunItem __instance) { Helpers.EndEnemyShot(__instance); } [HarmonyPostfix] private static void ApplyShotgunEnvironmentEffects(ShotgunItem __instance, Vector3 shotgunPosition, Vector3 shotgunForward) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)null && ((GrabbableObject)__instance).isHeld && !((GrabbableObject)__instance).isHeldByEnemy) { TemporaryRootClear.Trigger(); SpiderWebClear.TryClear(__instance, shotgunPosition, shotgunForward); } } internal static bool PreCheckFriendly(ShotgunItem shotgun) { if (!Plugin.Settings.DisableOutgoingFriendlyFire.Value) { return false; } return !((GrabbableObject)shotgun).isHeldByEnemy; } internal static int GetShotgunDamage(int originalDamage) { int value = Plugin.Settings.ShotgunDamage.Value; if (value >= 0) { return value; } return originalDamage; } [HarmonyTranspiler] private static IEnumerable<CodeInstruction> ShootGunTranspiler(IEnumerable<CodeInstruction> instructions) { bool injectedFriendlyFireCheck = false; foreach (CodeInstruction instruction in instructions) { if (!injectedFriendlyFireCheck && instruction.opcode == OpCodes.Stloc_0) { yield return instruction; yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null); yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ShotgunShootPatch), "PreCheckFriendly", (Type[])null, (Type[])null)); yield return new CodeInstruction(OpCodes.Stloc_0, (object)null); injectedFriendlyFireCheck = true; } else if (instruction.opcode == OpCodes.Ldc_I4_5) { yield return instruction; yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ShotgunShootPatch), "GetShotgunDamage", (Type[])null, (Type[])null)); } else { yield return instruction; } } } } [HarmonyPatch(typeof(ShotgunItem), "Update")] internal static class ShotgunUpdatePatch { [HarmonyPostfix] private static void UpdatePostfix(ShotgunItem __instance, ref float ___misfireTimer, ref bool ___hasHitGroundWithSafetyOff, ref int ___shellsLoaded) { if (!((Object)(object)__instance == (Object)null) && !((GrabbableObject)__instance).isHeldByEnemy) { if (Plugin.Settings.DisableShotgunMisfire.Value) { ___misfireTimer = 30f; ___hasHitGroundWithSafetyOff = false; } if (Plugin.Settings.InfiniteShotgunAmmo.Value && ___shellsLoaded < 2) { ___shellsLoaded = 2; } } } } [HarmonyPatch(typeof(PlayerControllerB), "DamagePlayer")] internal static class PlayerDamagePatch { [HarmonyPrefix] private static bool DamagePlayerPrefix(PlayerControllerB __instance, CauseOfDeath causeOfDeath, bool callRPC) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (Helpers.EnemyShotInProgress) { return true; } if (!Helpers.IsWeaponCause(causeOfDeath)) { return true; } PlayerControllerB localPlayer = Helpers.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return true; } if ((Object)(object)__instance == (Object)(object)localPlayer && Plugin.Settings.DisableIncomingFriendlyFire.Value) { return false; } if ((Object)(object)__instance != (Object)(object)localPlayer && callRPC && Plugin.Settings.DisableOutgoingFriendlyFire.Value) { return false; } return true; } } [HarmonyPatch(typeof(PlayerControllerB), "DamagePlayerFromOtherClientClientRpc")] internal static class IncomingNetworkDamagePatch { [HarmonyPrefix] private static bool IncomingPrefix(PlayerControllerB __instance) { PlayerControllerB localPlayer = Helpers.LocalPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)__instance != (Object)(object)localPlayer)) { return !Plugin.Settings.DisableIncomingFriendlyFire.Value; } return true; } } [HarmonyPatch(typeof(PlayerControllerB), "DamagePlayerFromOtherClientServerRpc")] internal static class OutgoingNetworkDamagePatch { [HarmonyPrefix] private static bool OutgoingPrefix(int playerWhoHit) { PlayerControllerB localPlayer = Helpers.LocalPlayer; if ((Object)(object)localPlayer == (Object)null || !Plugin.Settings.DisableOutgoingFriendlyFire.Value) { return true; } return playerWhoHit != (int)localPlayer.playerClientId; } } [HarmonyPatch(typeof(Shovel), "HitShovel")] internal static class ShovelPatch { [HarmonyPrefix] private static void HitShovelPrefix(ref int ___shovelHitForce) { int value = Plugin.Settings.ShovelDamage.Value; if (value >= 0) { ___shovelHitForce = value; } } } }