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 SpearFishing v1.0.2
SpearFishing.dll
Decompiled 4 hours agousing System; using System.Diagnostics; using System.Reflection; 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 UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("Valheim Overhaul")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Catch fish with spears, harpoons, bows and crossbows. Modern replacement for Korppis Spearfishing.")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2")] [assembly: AssemblyProduct("SpearFishing")] [assembly: AssemblyTitle("SpearFishing")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.2.0")] [module: UnverifiableCode] [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 SpearFishing { internal static class FishCorpse { internal const string KillRpc = "SpearFishing_Kill"; internal static readonly int DeadHash = StringExtensionMethods.GetStableHashCode("SpearFishing_Dead"); internal static bool IsMarkedDead(ZNetView nview) { if ((Object)(object)nview != (Object)null && nview.IsValid()) { return nview.GetZDO().GetBool(DeadHash, false); } return false; } internal static bool IsMarkedDead(Fish fish) { if ((Object)(object)fish != (Object)null) { return IsMarkedDead(fish.m_nview); } return false; } internal static void MarkDead(Fish fish) { if (!((Object)(object)fish?.m_nview == (Object)null) && fish.m_nview.IsValid()) { if (!fish.m_nview.IsOwner()) { fish.m_nview.ClaimOwnership(); } fish.m_nview.GetZDO().Set(DeadHash, true); } } internal static void RegisterKillRpc(Fish fish) { if ((Object)(object)fish?.m_nview == (Object)null || !fish.m_nview.IsValid()) { return; } ZNetView nview = fish.m_nview; nview.Register("SpearFishing_Kill", (Action<long>)delegate { Fish component = ((Component)nview).GetComponent<Fish>(); if ((Object)(object)component != (Object)null) { ConvertToCorpse(component); } }); } internal static void BroadcastKill(Fish fish) { if (!((Object)(object)fish?.m_nview == (Object)null) && fish.m_nview.IsValid()) { fish.m_nview.InvokeRPC(ZNetView.Everybody, "SpearFishing_Kill", Array.Empty<object>()); } } internal static bool ConvertToCorpse(Fish fish) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)fish == (Object)null) { return false; } if ((Object)(object)((Component)fish).GetComponent<SpearFishCorpseMarker>() != (Object)null) { return true; } GameObject gameObject = ((Component)fish).gameObject; ItemDrop component = ((Component)fish).GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { return false; } gameObject.AddComponent<SpearFishCorpseMarker>(); Rigidbody component2 = gameObject.GetComponent<Rigidbody>(); if ((Object)(object)component2 != (Object)null) { component2.linearVelocity = Vector3.zero; component2.angularVelocity = Vector3.zero; component2.useGravity = true; component2.isKinematic = false; } gameObject.transform.Rotate(0f, 0f, (Random.value > 0.5f) ? 90f : (-90f)); if (component.m_itemData != null && fish.m_pickupItemStackSize > 0) { component.m_itemData.m_stack = fish.m_pickupItemStackSize; } EnsureFloating(component, gameObject.transform.position); Object.Destroy((Object)(object)fish); return true; } internal static void EnsureFloating(ItemDrop drop, Vector3 position) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)drop == (Object)null)) { Floating val = drop.m_floating; if ((Object)(object)val == (Object)null) { val = ((Component)drop).GetComponent<Floating>(); } if ((Object)(object)val == (Object)null) { val = ((Component)drop).gameObject.AddComponent<Floating>(); } val.m_waterLevelOffset = 0.65f; drop.m_floating = val; float liquidLevel = Floating.GetLiquidLevel(position, 1f, (LiquidType)0); val.SetLiquidLevel(liquidLevel, (LiquidType)0, (Component)null); } } } internal sealed class SpearFishCorpseMarker : MonoBehaviour { } [HarmonyPatch(typeof(Projectile), "OnHit")] internal static class ProjectileOnHitPatch { private static readonly int HarpoonedHash = StringExtensionMethods.GetStableHashCode("Harpooned"); private static bool Prefix(Projectile __instance, Collider collider, Vector3 hitPoint, bool water) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)collider == (Object)null) { return true; } if (!TryGetLocalOwner(__instance, out var owner)) { return true; } Fish val = FindFish(collider); if ((Object)(object)val == (Object)null) { return true; } if (FishCorpse.IsMarkedDead(val) || (Object)(object)((Component)val).GetComponent<SpearFishCorpseMarker>() != (Object)null) { return true; } if (!IsCatchAllowed(val, __instance, out var harpoon)) { return true; } Vector3 position = ((Component)val).transform.position; string name = val.m_name; if (Plugin.DebugLog.Value) { Plugin.Log.LogInfo((object)$"Spear hit fish '{name}' with skill={__instance.m_skill}, harpoon={harpoon}, waterHit={water}"); } if (!((harpoon || Plugin.AutoPickupAll.Value) ? TryAutoPickup(val, owner, harpoon) : TryMakeCorpse(val, owner, name))) { return true; } PlayCatchEffects(position, __instance, hitPoint); FinishProjectile(__instance, hitPoint); return false; } private static bool TryGetLocalOwner(Projectile projectile, out Humanoid owner) { Character owner2 = projectile.m_owner; owner = (Humanoid)(object)((owner2 is Humanoid) ? owner2 : null); if ((Object)(object)owner == (Object)null) { return false; } if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)owner != (Object)(object)Player.m_localPlayer) { return false; } return true; } private static Fish FindFish(Collider collider) { GameObject val = Projectile.FindHitObject(collider); if ((Object)(object)val == (Object)null) { return null; } Fish component = val.GetComponent<Fish>(); if ((Object)(object)component != (Object)null) { return component; } return val.GetComponentInParent<Fish>(); } private static bool IsCatchAllowed(Fish fish, Projectile projectile, out bool harpoon) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Invalid comparison between Unknown and I4 //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Invalid comparison between Unknown and I4 //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 harpoon = IsHarpoon(projectile); if (Plugin.RequireInWater.Value && fish.IsOutOfWater()) { return false; } if (!Object.op_Implicit((Object)(object)fish.m_nview) || !fish.m_nview.IsValid()) { return false; } if (harpoon) { return Plugin.EnableHarpoons.Value; } SkillType skill = projectile.m_skill; if ((int)skill != 5) { if ((int)skill != 8) { if ((int)skill == 14) { return Plugin.EnableCrossbows.Value; } return IsEnabledByProjectileName(((Object)projectile).name); } return Plugin.EnableBows.Value; } return Plugin.EnableSpears.Value; } private static bool IsHarpoon(Projectile projectile) { if (projectile.m_statusEffectHash == HarpoonedHash) { return true; } string name = ((Object)projectile).name; if (string.IsNullOrEmpty(name)) { return false; } name = name.ToLowerInvariant(); if (!name.Contains("harpoon")) { return name.Contains("chitinharpoon"); } return true; } private static bool IsEnabledByProjectileName(string projectileName) { if (string.IsNullOrEmpty(projectileName)) { return false; } string text = projectileName.ToLowerInvariant(); if (text.Contains("harpoon") || text.Contains("chitinharpoon")) { return Plugin.EnableHarpoons.Value; } if (text.Contains("spear") || text.Contains("splitner") || text.Contains("wolffang")) { return Plugin.EnableSpears.Value; } if (text.Contains("bow_projectile") || text.Contains("arrow")) { return Plugin.EnableBows.Value; } if (text.Contains("arbalest") || text.Contains("bolt")) { return Plugin.EnableCrossbows.Value; } return false; } private static bool TryAutoPickup(Fish fish, Humanoid owner, bool harpoon) { if (!fish.Pickup(owner)) { return false; } if (Plugin.ShowMessages.Value) { string text = (harpoon ? " $msg_harpoon_harpooned" : " $msg_added"); ((Character)owner).Message((MessageType)2, fish.m_name + text, 0, (Sprite)null); } GrantXp(owner); return true; } private static bool TryMakeCorpse(Fish fish, Humanoid owner, string fishName) { if ((Object)(object)((Component)fish).GetComponent<ItemDrop>() == (Object)null) { return TryAutoPickup(fish, owner, harpoon: false); } ZNetView nview = fish.m_nview; FishCorpse.MarkDead(fish); FishCorpse.BroadcastKill(fish); Fish val = (((Object)(object)nview != (Object)null) ? ((Component)nview).GetComponent<Fish>() : null); if ((Object)(object)val != (Object)null && !FishCorpse.ConvertToCorpse(val)) { return false; } if (Plugin.ShowMessages.Value) { ((Character)owner).Message((MessageType)2, fishName, 0, (Sprite)null); } GrantXp(owner); return true; } private static void GrantXp(Humanoid owner) { if (Plugin.GrantFishingXp.Value && !((Object)(object)owner == (Object)null)) { float value = Plugin.FishingXpAmount.Value; if (!(value <= 0f)) { ((Character)owner).RaiseSkill((SkillType)104, value); } } } private static void PlayCatchEffects(Vector3 fishPos, Projectile projectile, Vector3 hitPoint) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.HitEffects.Value) { return; } if ((Object)(object)projectile != (Object)null && projectile.m_hitEffects != null) { projectile.m_hitEffects.Create(hitPoint, Quaternion.identity, (Transform)null, 1f, -1); } if (!((Object)(object)ZNetScene.instance == (Object)null)) { GameObject prefab = ZNetScene.instance.GetPrefab("fx_TickBloodHit"); if ((Object)(object)prefab != (Object)null) { Object.Instantiate<GameObject>(prefab, fishPos, Quaternion.identity); } } } private static void FinishProjectile(Projectile projectile, Vector3 hitPoint) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)projectile == (Object)null) { return; } projectile.m_didHit = true; ((Component)projectile).transform.position = hitPoint; if ((Object)(object)projectile.m_nview != (Object)null && projectile.m_nview.IsValid()) { if (projectile.m_nview.IsOwner()) { projectile.m_nview.InvokeRPC("RPC_OnHit", Array.Empty<object>()); ZNetScene.instance.Destroy(((Component)projectile).gameObject); } } else { Object.Destroy((Object)(object)((Component)projectile).gameObject); } } } [HarmonyPatch(typeof(Fish), "Start")] internal static class FishStartPatch { private static void Postfix(Fish __instance) { if (!((Object)(object)__instance == (Object)null)) { FishCorpse.RegisterKillRpc(__instance); if (FishCorpse.IsMarkedDead(__instance)) { FishCorpse.ConvertToCorpse(__instance); } } } } [BepInPlugin("valheimoverhaul.spearfishing", "SpearFishing", "1.0.2")] [BepInIncompatibility("org.bepinex.plugins.spearfishing")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "valheimoverhaul.spearfishing"; public const string PluginName = "SpearFishing"; public const string PluginVersion = "1.0.2"; internal static ManualLogSource Log; internal static ConfigEntry<bool> EnableSpears; internal static ConfigEntry<bool> EnableHarpoons; internal static ConfigEntry<bool> EnableBows; internal static ConfigEntry<bool> EnableCrossbows; internal static ConfigEntry<bool> AutoPickupAll; internal static ConfigEntry<bool> RequireInWater; internal static ConfigEntry<bool> GrantFishingXp; internal static ConfigEntry<float> FishingXpAmount; internal static ConfigEntry<bool> ShowMessages; internal static ConfigEntry<bool> HitEffects; internal static ConfigEntry<bool> DebugLog; private void Awake() { //IL_0174: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; EnableSpears = ((BaseUnityPlugin)this).Config.Bind<bool>("Weapons", "Enable Spears", true, "Catch fish with thrown spears."); EnableHarpoons = ((BaseUnityPlugin)this).Config.Bind<bool>("Weapons", "Enable Harpoons", true, "Catch fish with the Abyssal Harpoon (auto-pickup)."); EnableBows = ((BaseUnityPlugin)this).Config.Bind<bool>("Weapons", "Enable Bows", true, "Catch fish with bow arrows."); EnableCrossbows = ((BaseUnityPlugin)this).Config.Bind<bool>("Weapons", "Enable Crossbows", true, "Catch fish with crossbow bolts."); AutoPickupAll = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "Auto Pickup All", false, "If true, all enabled weapons auto-add fish to inventory. Harpoons always auto-pickup."); RequireInWater = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "Require In Water", true, "Only catch fish that are still swimming (not already stranded)."); GrantFishingXp = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "Grant Fishing XP", true, "Grant a small amount of Fishing skill XP on a successful catch."); FishingXpAmount = ((BaseUnityPlugin)this).Config.Bind<float>("Gameplay", "Fishing XP Amount", 0.5f, "Fishing skill XP granted per catch when Grant Fishing XP is enabled."); ShowMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("Feedback", "Show Messages", true, "Show center HUD messages when catching fish."); HitEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("Feedback", "Hit Effects", true, "Play hit / blood VFX when a fish is speared."); DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Debug Log", false, "Log catch attempts to the BepInEx log."); new Harmony("valheimoverhaul.spearfishing").PatchAll(); Log.LogInfo((object)"SpearFishing 1.0.2 loaded."); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }