using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] namespace BetterWeapons { [BepInPlugin("com.bacon.betterweapons", "BetterWeapons", "1.0.0")] public class Plugin : BaseUnityPlugin { public static ManualLogSource Log; public const string PLUGIN_GUID = "com.bacon.betterweapons"; public const string PLUGIN_NAME = "BetterWeapons"; public const string PLUGIN_VERSION = "1.0.0"; private readonly Harmony harmony = new Harmony("com.bacon.betterweapons"); private void Awake() { Log = ((BaseUnityPlugin)this).Logger; ModConfig.Init(((BaseUnityPlugin)this).Config); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin BetterWeapons is loaded!"); } } public static class ModConfig { public static ConfigEntry DisableShotgunMisfire { get; private set; } public static ConfigEntry DisableIncomingFriendlyFire { get; private set; } public static ConfigEntry DisableOutgoingFriendlyFire { get; private set; } public static ConfigEntry ShovelDamage { get; private set; } public static ConfigEntry ShotgunDamage { get; private set; } public static ConfigEntry InfiniteShotgunAmmo { get; private set; } public static void Init(ConfigFile config) { DisableShotgunMisfire = config.Bind("Shotgun", "DisableShotgunMisfire", true, "Prevents the shotgun from randomly misfiring."); DisableIncomingFriendlyFire = config.Bind("General", "DisableIncomingFriendlyFire", true, "Prevents you from taking damage from players."); DisableOutgoingFriendlyFire = config.Bind("General", "DisableOutgoingFriendlyFire", true, "Prevents you from damaging other players."); InfiniteShotgunAmmo = config.Bind("Shotgun", "InfiniteShotgunAmmo", true, "Prevents the shotgun from consuming ammo."); ShotgunDamage = config.Bind("Shotgun", "ShotgunDamage", -1, "Custom shotgun damage. Set to -1 to use default (which is usually 5)."); ShovelDamage = config.Bind("Shovel", "ShovelDamage", 2, "Custom shovel damage. (Default is 1)."); } } } namespace BetterWeapons.Patches { [HarmonyPatch(typeof(ShotgunItem))] public static class ShotgunPatch { public static bool PreCheckFriendly(ShotgunItem shotgun) { if (!ModConfig.DisableOutgoingFriendlyFire.Value) { return false; } return !((GrabbableObject)shotgun).isHeldByEnemy; } public static int GetShotgunDamage(int defaultDamage) { if (ModConfig.ShotgunDamage.Value == -1) { return defaultDamage; } return ModConfig.ShotgunDamage.Value; } [HarmonyPatch("ShootGun")] [HarmonyPrefix] private static bool ShootGunPrefix(ShotgunItem __instance) { if (ModConfig.DisableShotgunMisfire.Value && !((GrabbableObject)__instance).isHeld && !((GrabbableObject)__instance).isHeldByEnemy) { return false; } return true; } [HarmonyPatch("ShootGun")] [HarmonyTranspiler] private static IEnumerable ShootGunTranspiler(IEnumerable instructions) { bool pendingFriendlyFire = true; foreach (CodeInstruction inst in instructions) { if (pendingFriendlyFire && inst.opcode == OpCodes.Stloc_0) { yield return inst; yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null); yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ShotgunPatch), "PreCheckFriendly", (Type[])null, (Type[])null)); yield return new CodeInstruction(OpCodes.Stloc_0, (object)null); pendingFriendlyFire = false; } else if (inst.opcode == OpCodes.Ldc_I4_5) { yield return new CodeInstruction(OpCodes.Ldc_I4_5, (object)null); yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ShotgunPatch), "GetShotgunDamage", (Type[])null, (Type[])null)); } else { yield return inst; } } } [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdatePostfix(ShotgunItem __instance, ref float ___misfireTimer, ref bool ___hasHitGroundWithSafetyOff, ref int ___shellsLoaded) { if (ModConfig.DisableShotgunMisfire.Value) { ___misfireTimer = 30f; ___hasHitGroundWithSafetyOff = false; } if (ModConfig.InfiniteShotgunAmmo.Value && ___shellsLoaded < 2) { ___shellsLoaded = 2; } } } [HarmonyPatch(typeof(Shovel))] public static class ShovelPatch { [HarmonyPatch("HitShovel")] [HarmonyPrefix] private static void HitShovelPrefix(Shovel __instance, ref int ___shovelHitForce) { ___shovelHitForce = ModConfig.ShovelDamage.Value; } } [HarmonyPatch(typeof(PlayerControllerB))] public static class PlayerDamagePatch { [HarmonyPatch("DamagePlayer")] [HarmonyPrefix] private static bool DamagePlayerPrefix(PlayerControllerB __instance, int damageNumber, CauseOfDeath causeOfDeath, bool callRPC = true) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Invalid comparison between Unknown and I4 //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Invalid comparison between Unknown and I4 //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Invalid comparison between Unknown and I4 //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Invalid comparison between Unknown and I4 //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) Plugin.Log.LogInfo((object)$"[BetterWeapons] DamagePlayer called! Victim: {__instance.playerUsername}, Damage: {damageNumber}, Cause: {causeOfDeath}, RPC: {callRPC}"); if ((Object)(object)__instance == (Object)(object)GameNetworkManager.Instance.localPlayerController) { Plugin.Log.LogInfo((object)"[BetterWeapons] DamagePlayer is targeting the local player. Checking incoming friendly fire config..."); if (ModConfig.DisableIncomingFriendlyFire.Value && ((int)causeOfDeath == 7 || (int)causeOfDeath == 1)) { Plugin.Log.LogInfo((object)$"[BetterWeapons] Blocked incoming damage to local player! Cause: {causeOfDeath}"); return false; } } else { Plugin.Log.LogInfo((object)"[BetterWeapons] DamagePlayer is targeting a remote player. Checking outgoing friendly fire config..."); if (ModConfig.DisableOutgoingFriendlyFire.Value && callRPC && ((int)causeOfDeath == 7 || (int)causeOfDeath == 1)) { Plugin.Log.LogInfo((object)$"[BetterWeapons] Blocked outgoing damage from local player! Cause: {causeOfDeath}"); return false; } } return true; } [HarmonyPatch("DamagePlayerFromOtherClientClientRpc")] [HarmonyPrefix] private static bool IncomingNetworkedFriendlyFirePatch(PlayerControllerB __instance, int damageAmount, int playerWhoHit) { Plugin.Log.LogInfo((object)$"[BetterWeapons] DamagePlayerFromOtherClientClientRpc received! Victim: {__instance.playerUsername}, Damage: {damageAmount}, Attacker ID: {playerWhoHit}"); if ((Object)(object)__instance == (Object)(object)GameNetworkManager.Instance.localPlayerController) { Plugin.Log.LogInfo((object)"[BetterWeapons] RPC is targeting the local player. Checking incoming friendly fire config..."); if (ModConfig.DisableIncomingFriendlyFire.Value) { Plugin.Log.LogInfo((object)$"[BetterWeapons] Blocked incoming networked damage to local player! Damage: {damageAmount}"); return false; } } return true; } [HarmonyPatch("DamagePlayerFromOtherClientServerRpc")] [HarmonyPrefix] private static bool OutgoingNetworkedFriendlyFirePatch(PlayerControllerB __instance, int damageAmount, int playerWhoHit) { Plugin.Log.LogInfo((object)$"[BetterWeapons] DamagePlayerFromOtherClientServerRpc sending! Victim: {__instance.playerUsername}, Damage: {damageAmount}, Attacker ID: {playerWhoHit}"); if ((Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null && playerWhoHit == (int)GameNetworkManager.Instance.localPlayerController.playerClientId) { Plugin.Log.LogInfo((object)"[BetterWeapons] RPC is being sent by the local player. Checking outgoing friendly fire config..."); if (ModConfig.DisableOutgoingFriendlyFire.Value) { Plugin.Log.LogInfo((object)$"[BetterWeapons] Blocked outgoing networked damage from local player! Damage: {damageAmount}"); return false; } } return true; } } }