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 Fish Easily v1.0.0
FishEasily.dll
Decompiled 3 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; 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: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("FishEasily")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Valheim fishing without the fight.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+59c081ce96977925e9036fdba4d0aa560aca9845")] [assembly: AssemblyProduct("Fish-Easily")] [assembly: AssemblyTitle("FishEasily")] [assembly: AssemblyVersion("1.0.0.0")] [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 FishEasily { internal static class FishingPatches { [HarmonyPatch(typeof(Fish), "TestBate")] private static class Fish_TestBate { private static bool Prefix(ref bool __result) { if (!Plugin.OneBaitFitsAll.Value) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Fish), "FindFloat")] private static class Fish_FindFloat { private static bool Prefix(Fish __instance, ref FishingFloat __result) { if (!Plugin.FishComeToYou.Value) { return true; } __result = NearestFloat(__instance); return false; } } [HarmonyPatch(typeof(Fish), "Escape")] private static class Fish_Escape { private static bool Prefix() { return !Plugin.FishNeverEscape.Value; } } [HarmonyPatch(typeof(Fish), "GetStaminaUse")] private static class Fish_GetStaminaUse { private static bool Prefix(ref float __result) { if (!Plugin.NoStaminaDrain.Value) { return true; } __result = 0f; return false; } } [HarmonyPatch(typeof(FishingFloat), "Awake")] private static class FishingFloat_Awake { private static void Postfix(FishingFloat __instance) { if (Plugin.NoStaminaDrain.Value) { __instance.m_pullStaminaUse = 0f; __instance.m_pullStaminaUseMaxSkillMultiplier = 0f; __instance.m_hookedStaminaPerSec = 0f; __instance.m_hookedStaminaPerSecMaxSkill = 0f; } if (Plugin.LineNeverBreaks.Value) { __instance.m_breakDistance = 100000f; __instance.m_maxDistance = 100000f; } } } [HarmonyPatch(typeof(FishingFloat), "FixedUpdate")] private static class FishingFloat_FixedUpdate { private static bool Prefix(FishingFloat __instance) { try { if (!Ready) { return true; } ZNetView val = _nview.Invoke(__instance); if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner()) { return true; } if (Plugin.AutoHook.Value && (Object)(object)__instance.GetCatch() == (Object)null) { Fish val2 = _nibbler.Invoke(__instance); if ((Object)(object)val2 != (Object)null && Time.time - _nibbleTime.Invoke(__instance) < 0.5f) { Hook(__instance, val2); } } if (Plugin.InstantLand.Value) { Fish val3 = __instance.GetCatch(); if ((Object)(object)val3 != (Object)null && Land(__instance, val3)) { return false; } } } catch (Exception ex) { if (!_fixedUpdateErrorLogged) { _fixedUpdateErrorLogged = true; Plugin.Log.LogError((object)("Fish-Easily FixedUpdate patch failed (repeats suppressed): " + ex)); } } return true; } } [HarmonyPatch(typeof(FishingFloat), "Catch")] private static class FishingFloat_Catch { private static void Prefix(Fish fish) { if (Plugin.BaitNotConsumed.Value && _baitConsumed != null && !(_returnBait == null)) { FishingFloat val = FishingFloat.FindFloat(fish); if (!((Object)(object)val == (Object)null)) { _baitConsumed.Invoke(val) = false; _returnBait.Invoke(val, null); } } } } private static FieldRef<FishingFloat, Fish> _nibbler; private static FieldRef<FishingFloat, float> _nibbleTime; private static FieldRef<FishingFloat, bool> _baitConsumed; private static FieldRef<FishingFloat, ZNetView> _nview; private static FieldRef<Fish, FishingFloat> _failedBait; private static MethodInfo _setCatch; private static MethodInfo _returnBait; private static MethodInfo _getOwner; private static readonly List<string> Missing = new List<string>(); private static bool _fixedUpdateErrorLogged; private static bool Ready { get { if (_nibbler != null && _nibbleTime != null && _baitConsumed != null && _nview != null && _setCatch != null) { return _getOwner != null; } return false; } } internal static void ResolveTargets() { Missing.Clear(); _nibbler = Try(() => AccessTools.FieldRefAccess<FishingFloat, Fish>("m_nibbler"), "FishingFloat.m_nibbler"); _nibbleTime = Try(() => AccessTools.FieldRefAccess<FishingFloat, float>("m_nibbleTime"), "FishingFloat.m_nibbleTime"); _baitConsumed = Try(() => AccessTools.FieldRefAccess<FishingFloat, bool>("m_baitConsumed"), "FishingFloat.m_baitConsumed"); _nview = Try(() => AccessTools.FieldRefAccess<FishingFloat, ZNetView>("m_nview"), "FishingFloat.m_nview"); _failedBait = Try(() => AccessTools.FieldRefAccess<Fish, FishingFloat>("m_failedBait"), "Fish.m_failedBait"); _setCatch = TryMethod("FishingFloat.SetCatch"); _returnBait = TryMethod("FishingFloat.ReturnBait"); _getOwner = TryMethod("FishingFloat.GetOwner"); if (Missing.Count > 0) { Plugin.Log.LogError((object)("Fish-Easily: " + Missing.Count + " member(s) not found in this Valheim build: " + string.Join(", ", Missing))); Plugin.Log.LogError((object)"Fish-Easily will still load, but the features that rely on them are disabled."); } else { Plugin.Log.LogInfo((object)"Fish-Easily: all patch targets resolved against this Valheim build."); } } private static T Try<T>(Func<T> f, string label) where T : class { try { T val = f(); if (val == null) { Missing.Add(label); } return val; } catch (Exception) { Missing.Add(label); return null; } } private static MethodInfo TryMethod(string label) { try { string[] array = label.Split(new char[1] { '.' }); MethodInfo methodInfo = AccessTools.Method(AccessTools.TypeByName(array[0]), array[1], (Type[])null, (Type[])null); if (methodInfo == null) { Missing.Add(label); } return methodInfo; } catch (Exception) { Missing.Add(label); return null; } } private static FishingFloat NearestFloat(Fish fish) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) FishingFloat result = null; float num = float.MaxValue; FishingFloat val = ((_failedBait != null) ? _failedBait.Invoke(fish) : null); foreach (FishingFloat allInstance in FishingFloat.GetAllInstances()) { if (!((Object)(object)allInstance == (Object)null) && allInstance.IsInWater() && !((Object)(object)allInstance.GetCatch() != (Object)null) && !((Object)(object)allInstance == (Object)(object)val)) { float num2 = Vector3.Distance(((Component)fish).transform.position, ((Component)allInstance).transform.position); if (!(num2 > allInstance.m_range) && num2 < num) { num = num2; result = allInstance; } } } return result; } private static void Hook(FishingFloat ff, Fish fish) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown Character val = (Character)_getOwner.Invoke(ff, null); _setCatch.Invoke(ff, new object[1] { fish }); _nibbler.Invoke(ff) = null; Game.instance.IncrementPlayerStat((PlayerStatType)158, 1f, false); if ((Object)(object)val != (Object)null) { Message(ff, val, "$msg_fishing_hooked"); } } private static bool Land(FishingFloat ff, Fish fish) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown Character val = (Character)_getOwner.Invoke(ff, null); if ((Object)(object)val == (Object)null) { return false; } string msg = FishingFloat.Catch(fish, val); Message(ff, val, msg); _setCatch.Invoke(ff, new object[1]); fish.OnHooked((FishingFloat)null); ZNetView val2 = _nview.Invoke(ff); if ((Object)(object)val2 != (Object)null) { val2.Destroy(); } return true; } private static void Message(FishingFloat ff, Character owner, string msg) { if (!string.IsNullOrEmpty(msg)) { owner.Message((MessageType)2, Localization.instance.Localize(msg), 0, (Sprite)null, false); } } } [BepInPlugin("valheim.fisheasily", "Fish-Easily", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "valheim.fisheasily"; public const string Version = "1.0.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> OneBaitFitsAll; internal static ConfigEntry<bool> BaitNotConsumed; internal static ConfigEntry<bool> FishComeToYou; internal static ConfigEntry<bool> AutoHook; internal static ConfigEntry<bool> NoStaminaDrain; internal static ConfigEntry<bool> FishNeverEscape; internal static ConfigEntry<bool> InstantLand; internal static ConfigEntry<bool> LineNeverBreaks; private Harmony _harmony; private void Awake() { //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; OneBaitFitsAll = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Bait", "One Bait Fits All", true, "Any bait catches any fish. Vanilla only bites when the fish's own bait table matches what is on your line, which is why you end up carrying five bait types."); BaitNotConsumed = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - Bait", "Bait Not Consumed", true, "Put the bait back in your inventory after a catch, so one stack lasts forever."); FishComeToYou = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - The Bite", "Fish Come To You", true, "Fish always swim towards your float instead of only sometimes noticing it. Nothing is spawned; it only removes the coin-flip in Fish.FindFloat."); AutoHook = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - The Bite", "Auto Hook", true, "Hook the fish the moment it nibbles. No reaction timing."); NoStaminaDrain = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - The Fight", "No Stamina Drain", true, "Reeling and holding a hooked fish cost no stamina, so you never lose a fish to an empty bar mid-fight."); FishNeverEscape = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - The Fight", "Fish Never Escape", true, "Fish never do their escape struggle (the thing that halves reel speed and doubles stamina drain)."); InstantLand = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - The Fight", "Instant Land", true, "The fish is landed the moment it is hooked. No tug-of-war, no button hold. Turn this off to keep the fight but keep every other convenience."); LineNeverBreaks = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - The Line", "Line Never Breaks", true, "The line cannot snap from distance or from a fighting fish."); FishingPatches.ResolveTargets(); _harmony = new Harmony("valheim.fisheasily"); _harmony.PatchAll(typeof(Plugin).Assembly); VerifyPatches(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Fish-Easily 1.0.0 loaded - fishing is now a foregone conclusion."); } private void VerifyPatches() { List<MethodBase> list = new List<MethodBase>(_harmony.GetPatchedMethods()); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Fish-Easily: Harmony reports {list.Count} patched method(s)."); foreach (MethodBase item in list) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(" patched: " + item.DeclaringType?.Name + "." + item.Name)); } } } }