using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("StopBitingMyBoat")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("StopBitingMyBoat")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("72f52b69-822e-4c14-902a-cdb9805a310d")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace StopBitingMyBoat { [BepInPlugin("petri.valheim.stopbitingmyboat", "Stop Biting My Boat", "1.0.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; public const string ModGuid = "petri.valheim.stopbitingmyboat"; public const string ModName = "Stop Biting My Boat"; public const string ModVersion = "1.0.0"; internal static ConfigEntry ModEnabled; internal static ConfigEntry DebugLogging; internal static ConfigEntry OnlyIgnoreEmptyBoats; internal static ConfigEntry PreventBoatDamage; private Harmony _harmony; private void Awake() { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown ModEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enable or disable Stop Biting My Boat."); DebugLogging = ((BaseUnityPlugin)this).Config.Bind("General", "DebugLogging", false, "Enable debug logging."); OnlyIgnoreEmptyBoats = ((BaseUnityPlugin)this).Config.Bind("General", "OnlyIgnoreEmptyBoats", false, "If enabled, Necks and Boars only ignore boats when no player is onboard."); PreventBoatDamage = ((BaseUnityPlugin)this).Config.Bind("General", "PreventBoatDamage", true, "Prevent Necks and Boars from damaging boats if they still manage to attack."); Log = ((BaseUnityPlugin)this).Logger; _harmony = new Harmony("petri.valheim.stopbitingmyboat"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Stop Biting My Boat loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal static void LogDebug(string message) { if (DebugLogging.Value) { Log.LogInfo((object)message); } } } } namespace StopBitingMyBoat.Patches { public static class StaticTargetFilter { public static void FilterBoatTarget(BaseAI ai, ref StaticTarget target, string source) { if (!Plugin.ModEnabled.Value || (Object)(object)ai == (Object)null || (Object)(object)target == (Object)null) { return; } string text = ((Object)((Component)ai).gameObject).name.Replace("(Clone)", ""); if (!(text != "Neck") || !(text != "Boar")) { Plugin.LogDebug("Static target found from " + source + ": AI=" + text + ", Target=" + ((Object)target).name + ", Root=" + ((Object)((Component)target).transform.root).name); Ship val = ((Component)target).GetComponentInParent(); if ((Object)(object)val == (Object)null) { val = ((Component)((Component)target).transform.root).GetComponent(); } if ((Object)(object)val == (Object)null) { Plugin.LogDebug(text + " static target was not detected as ship: Target=" + ((Object)target).name + ", Root=" + ((Object)((Component)target).transform.root).name); } else if (Plugin.OnlyIgnoreEmptyBoats.Value && val.HasPlayerOnboard()) { Plugin.LogDebug(text + " allowed boat target because player is onboard: " + ((Object)val).name); } else { Plugin.LogDebug(text + " ignored boat static target from " + source + ": " + ((Object)val).name); target = null; } } } } [HarmonyPatch(typeof(BaseAI), "FindClosestStaticPriorityTarget")] public static class BaseAI_FindClosestStaticPriorityTargetPatch { [HarmonyPostfix] private static void Postfix(BaseAI __instance, ref StaticTarget __result) { StaticTargetFilter.FilterBoatTarget(__instance, ref __result, "closest priority"); } } [HarmonyPatch(typeof(BaseAI), "FindRandomStaticTarget")] public static class BaseAI_FindRandomStaticTargetPatch { [HarmonyPostfix] private static void Postfix(BaseAI __instance, ref StaticTarget __result) { StaticTargetFilter.FilterBoatTarget(__instance, ref __result, "random"); } } [HarmonyPatch(typeof(WearNTear), "Damage")] public static class WearNTearDamagePatch { [HarmonyPrefix] private static bool Prefix(WearNTear __instance, HitData hit) { if (!Plugin.ModEnabled.Value) { return true; } if (!Plugin.PreventBoatDamage.Value) { return true; } if ((Object)(object)__instance == (Object)null || hit == null) { return true; } if ((Object)(object)((Component)__instance).GetComponent() == (Object)null) { return true; } Character attacker = hit.GetAttacker(); string text = (((Object)(object)attacker != (Object)null) ? ((Object)((Component)attacker).gameObject).name.Replace("(Clone)", "") : "UNKNOWN"); if (text == "Neck" || text == "Boar") { Plugin.LogDebug("Blocked " + text + " damage to boat: " + ((Object)__instance).name); return false; } return true; } } }