Decompiled source of SpearFishing v2.0.1

SpearFishing.dll

Decompiled 2 months ago
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<Fish>() ?? val.GetComponentInParent<Fish>();
		}

		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<Floating>();
				}
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)drop).gameObject.AddComponent<Floating>();
				}
				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<ItemDrop>();
			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<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))
			{
				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<object>());
					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<bool> EnableSpears;

		internal static ConfigEntry<bool> EnableHarpoons;

		internal static ConfigEntry<bool> EnableBows;

		internal static ConfigEntry<bool> EnableCrossbows;

		internal static ConfigEntry<bool> RequireInWater;

		internal static ConfigEntry<int> RawFishAmount;

		internal static ConfigEntry<string> RawFishPrefab;

		internal static ConfigEntry<bool> AutoPickupHarpoon;

		internal static ConfigEntry<bool> AutoPickupAll;

		internal static ConfigEntry<bool> FloatWorldDrops;

		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_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<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.");
			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.");
			RequireInWater = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "Require In Water", true, "Only catch swimming fish (not already stranded).");
			RawFishAmount = ((BaseUnityPlugin)this).Config.Bind<int>("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<int>(1, 5), Array.Empty<object>()));
			RawFishPrefab = ((BaseUnityPlugin)this).Config.Bind<string>("Gameplay", "Raw Fish Prefab", "FishRaw", "ObjectDB prefab name for the drop (vanilla Raw fish).");
			AutoPickupHarpoon = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "Auto Pickup Harpoon", true, "Harpoon adds Raw fish straight to inventory when there is room.");
			AutoPickupAll = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "Auto Pickup All", false, "All enabled weapons auto-add Raw fish to inventory.");
			FloatWorldDrops = ((BaseUnityPlugin)this).Config.Bind<bool>("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<bool>("Gameplay", "Grant Fishing XP", true, "Grant a little Fishing XP on a catch.");
			FishingXpAmount = ((BaseUnityPlugin)this).Config.Bind<float>("Gameplay", "Fishing XP Amount", 0.35f, "Fishing XP per speared fish.");
			ShowMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("Feedback", "Show Messages", true, "Center HUD messages on catch.");
			HitEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("Feedback", "Hit Effects", true, "Hit / blood VFX on catch.");
			DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("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)
		{
		}
	}
}