using 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("Spear fish for Raw Fish. Rod fishing and prep table stay vanilla.")] [assembly: AssemblyFileVersion("2.0.1.0")] [assembly: AssemblyInformationalVersion("2.0.1")] [assembly: AssemblyProduct("SpearFishing")] [assembly: AssemblyTitle("SpearFishing")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.1.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 { [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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: 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 (!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 catch '{name}' skill={__instance.m_skill} harpoon={harpoon} waterHit={water}"); } bool flag = (harpoon && Plugin.AutoPickupHarpoon.Value) || Plugin.AutoPickupAll.Value; if (!TryHarvestRawFish(val, owner, flag, position)) { return true; } if (Plugin.ShowMessages.Value) { string text = (flag ? "$item_fish_raw $msg_added" : name); ((Character)owner).Message((MessageType)2, text, 0, (Sprite)null); } GrantXp(owner); 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) { return (Object)(object)owner == (Object)(object)Player.m_localPlayer; } return false; } private static Fish FindFish(Collider collider) { GameObject val = Projectile.FindHitObject(collider); if ((Object)(object)val == (Object)null) { return null; } return val.GetComponent() ?? val.GetComponentInParent(); } private static bool IsCatchAllowed(Fish fish, Projectile projectile, out bool harpoon) { //IL_004b: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Invalid comparison between Unknown and I4 //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Invalid comparison between Unknown and I4 //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Invalid comparison between Unknown and I4 harpoon = IsHarpoon(projectile); if (Plugin.RequireInWater.Value && fish.IsOutOfWater()) { return false; } if ((Object)(object)fish.m_nview == (Object)null || !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 TryHarvestRawFish(Fish fish, Humanoid owner, bool autoPickup, Vector3 position) { //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) if (!TryGetRawFishPrefab(out var prefab, out var data)) { Plugin.Log.LogWarning((object)("Could not find raw fish prefab '" + Plugin.RawFishPrefab.Value + "'. Catch aborted.")); return false; } int num = Mathf.Clamp(Plugin.RawFishAmount.Value, 1, 5); ZNetView nview = fish.m_nview; if (!nview.IsOwner()) { nview.ClaimOwnership(); } ZNetScene.instance.Destroy(((Component)fish).gameObject); if (autoPickup) { Player val = (Player)(object)((owner is Player) ? owner : null); if ((Object)(object)val != (Object)null && ((Humanoid)val).GetInventory().CanAddItem(prefab, num)) { if (((Humanoid)val).PickupPrefab(prefab, num, true) != null) { return true; } } else { ((Character)owner).Message((MessageType)2, "$msg_noroom", 0, (Sprite)null); } } ItemDrop val2 = ItemDrop.DropItem(data, num, position, Quaternion.identity); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)"Failed to spawn FishRaw drop."); return false; } if (Plugin.FloatWorldDrops.Value) { EnsureInstanceFloats(val2, position); } return true; } private static void EnsureInstanceFloats(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(); } if ((Object)(object)val == (Object)null) { val = ((Component)drop).gameObject.AddComponent(); } val.m_waterLevelOffset = 0.5f; drop.m_floating = val; float liquidLevel = Floating.GetLiquidLevel(position, 1f, (LiquidType)0); val.SetLiquidLevel(liquidLevel, (LiquidType)0, (Component)null); } } private static bool TryGetRawFishPrefab(out GameObject prefab, out ItemData data) { prefab = null; data = null; if ((Object)(object)ObjectDB.instance == (Object)null) { return false; } string text = Plugin.RawFishPrefab.Value; if (string.IsNullOrWhiteSpace(text)) { text = "FishRaw"; } prefab = ObjectDB.instance.GetItemPrefab(text.Trim()); if ((Object)(object)prefab == (Object)null) { string[] array = new string[3] { "FishRaw", "Fish_raw", "RawFish" }; foreach (string text2 in array) { prefab = ObjectDB.instance.GetItemPrefab(text2); if ((Object)(object)prefab != (Object)null) { break; } } } if ((Object)(object)prefab == (Object)null) { return false; } ItemDrop component = prefab.GetComponent(); if (component?.m_itemData == null) { return false; } data = component.m_itemData.Clone(); if ((Object)(object)data.m_dropPrefab == (Object)null) { data.m_dropPrefab = prefab; } 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_0058: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.HitEffects.Value) { return; } if (projectile != null) { EffectList hitEffects = projectile.m_hitEffects; if (hitEffects != null) { 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(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)) { projectile.m_didHit = true; ((Component)projectile).transform.position = hitPoint; if ((Object)(object)projectile.m_nview != (Object)null && projectile.m_nview.IsValid() && projectile.m_nview.IsOwner()) { projectile.m_nview.InvokeRPC("RPC_OnHit", Array.Empty()); ZNetScene.instance.Destroy(((Component)projectile).gameObject); } else if ((Object)(object)projectile.m_nview == (Object)null || !projectile.m_nview.IsValid()) { Object.Destroy((Object)(object)((Component)projectile).gameObject); } } } } [BepInPlugin("valheimoverhaul.spearfishing", "SpearFishing", "2.0.1")] [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 = "2.0.1"; internal static ManualLogSource Log; internal static ConfigEntry EnableSpears; internal static ConfigEntry EnableHarpoons; internal static ConfigEntry EnableBows; internal static ConfigEntry EnableCrossbows; internal static ConfigEntry RequireInWater; internal static ConfigEntry RawFishAmount; internal static ConfigEntry RawFishPrefab; internal static ConfigEntry AutoPickupHarpoon; internal static ConfigEntry AutoPickupAll; internal static ConfigEntry FloatWorldDrops; internal static ConfigEntry GrantFishingXp; internal static ConfigEntry FishingXpAmount; internal static ConfigEntry ShowMessages; internal static ConfigEntry HitEffects; internal static ConfigEntry DebugLog; private void Awake() { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_0209: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; EnableSpears = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Enable Spears", true, "Catch fish with thrown spears."); EnableHarpoons = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Enable Harpoons", true, "Catch fish with the Abyssal Harpoon."); EnableBows = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Enable Bows", true, "Catch fish with bow arrows."); EnableCrossbows = ((BaseUnityPlugin)this).Config.Bind("Weapons", "Enable Crossbows", true, "Catch fish with crossbow bolts."); RequireInWater = ((BaseUnityPlugin)this).Config.Bind("Gameplay", "Require In Water", true, "Only catch swimming fish (not already stranded)."); RawFishAmount = ((BaseUnityPlugin)this).Config.Bind("Gameplay", "Raw Fish Amount", 1, new ConfigDescription("How many FishRaw drop per speared fish. Rod fishing and the prep table are unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 5), Array.Empty())); RawFishPrefab = ((BaseUnityPlugin)this).Config.Bind("Gameplay", "Raw Fish Prefab", "FishRaw", "ObjectDB prefab name for the drop (vanilla Raw fish)."); AutoPickupHarpoon = ((BaseUnityPlugin)this).Config.Bind("Gameplay", "Auto Pickup Harpoon", true, "Harpoon adds Raw fish straight to inventory when there is room."); AutoPickupAll = ((BaseUnityPlugin)this).Config.Bind("Gameplay", "Auto Pickup All", false, "All enabled weapons auto-add Raw fish to inventory."); FloatWorldDrops = ((BaseUnityPlugin)this).Config.Bind("Gameplay", "Float World Drops", true, "Add Floating only to spearfishing FishRaw drops (instance), so they bob on water like wood. Does not change the FishRaw prefab."); GrantFishingXp = ((BaseUnityPlugin)this).Config.Bind("Gameplay", "Grant Fishing XP", true, "Grant a little Fishing XP on a catch."); FishingXpAmount = ((BaseUnityPlugin)this).Config.Bind("Gameplay", "Fishing XP Amount", 0.35f, "Fishing XP per speared fish."); ShowMessages = ((BaseUnityPlugin)this).Config.Bind("Feedback", "Show Messages", true, "Center HUD messages on catch."); HitEffects = ((BaseUnityPlugin)this).Config.Bind("Feedback", "Hit Effects", true, "Hit / blood VFX on catch."); DebugLog = ((BaseUnityPlugin)this).Config.Bind("Debug", "Debug Log", false, "Log catches to BepInEx."); new Harmony("valheimoverhaul.spearfishing").PatchAll(); Log.LogInfo((object)"SpearFishing 2.0.1 loaded (raw drops + instance float, no Fish update patches)."); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }