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 FishBreedingBasket v0.1.8
BepInEx/plugins/FishBreeding/FishBreeding.dll
Decompiled 5 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("FishBreeding")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("FishBreeding")] [assembly: AssemblyTitle("FishBreeding")] [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 ValheimFishBreeding { internal sealed class BasketColliderInteraction : MonoBehaviour, Hoverable, Interactable { private FishPondMarker FindMarker() { return ((Component)this).GetComponentInParent<FishPondMarker>(); } public string GetHoverName() { return LocalizationManager.Instance.TryTranslate("$piece_fbb_basket"); } public string GetHoverText() { return GetHoverName() + "\n[<color=yellow><b>E</b></color>] " + LocalizationManager.Instance.TryTranslate("$piece_fbb_collect"); } public float GetHoverOffset() { return 0f; } public bool Interact(Humanoid user, bool hold, bool alt) { if (!hold) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null) { FishPondMarker fishPondMarker = FindMarker(); if ((Object)(object)fishPondMarker == (Object)null) { return false; } fishPondMarker.CollectSurplus(val); return true; } } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } } [HarmonyPatch(typeof(Sign), "Interact", new Type[] { typeof(Humanoid), typeof(bool), typeof(bool) })] internal static class BasketSignInteractPatch { private static bool Prefix(Sign __instance, Humanoid character, bool hold, bool alt, ref bool __result) { FishPondMarker componentInParent = ((Component)__instance).GetComponentInParent<FishPondMarker>(); if ((Object)(object)componentInParent == (Object)null) { return true; } __result = false; if (!hold) { Player val = (Player)(object)((character is Player) ? character : null); if (val != null) { componentInParent.CollectSurplus(val); __result = true; return false; } } return false; } } [HarmonyPatch(typeof(Sign), "GetHoverText")] internal static class BasketSignHoverPatch { private static bool Prefix(Sign __instance, ref string __result) { if ((Object)(object)((Component)__instance).GetComponentInParent<FishPondMarker>() == (Object)null) { return true; } __result = LocalizationManager.Instance.TryTranslate("$piece_fbb_basket") + "\n[<color=yellow><b>E</b></color>] " + LocalizationManager.Instance.TryTranslate("$piece_fbb_collect"); return false; } } [HarmonyPatch(typeof(Sign), "GetHoverName")] internal static class BasketSignNamePatch { private static bool Prefix(Sign __instance, ref string __result) { if ((Object)(object)((Component)__instance).GetComponentInParent<FishPondMarker>() == (Object)null) { return true; } __result = LocalizationManager.Instance.TryTranslate("$piece_fbb_basket"); return false; } } [BepInPlugin("community.valheim.fishbreeding", "Fish Breeding - Natural Fish Ponds", "0.1.7.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class FishBreedingPlugin : BaseUnityPlugin { public const string ModGuid = "community.valheim.fishbreeding"; public const string ModName = "Fish Breeding - Natural Fish Ponds"; public const string ModVersion = "0.1.7.2"; public const string MarkerPrefabName = "FishBreeding_PondMarker"; private const string BundleFileName = "fishbreedingbasket"; private static AssetBundle _basketBundle; internal static FishBreedingPlugin Instance; internal static ConfigEntry<float> PondRadius; internal static ConfigEntry<float> ParentMaxDistance; internal static ConfigEntry<int> BreedingMinutes; internal static ConfigEntry<int> MaxFishPerPond; internal static ConfigEntry<bool> ModEnabled; internal static ConfigEntry<bool> PreventWallEscape; internal static ConfigEntry<float> ContainmentInterval; private void Awake() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Expected O, but got Unknown //IL_0182: Unknown result type (might be due to invalid IL or missing references) Instance = this; ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable breeding around a Fish Breeding Basket (existing marker saves are supported)."); PondRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Pond", "RadiusMeters", 12f, new ConfigDescription("Fish-counting radius around the basket.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 25f), Array.Empty<object>())); ParentMaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Pond", "ParentsWithinMeters", 6f, new ConfigDescription("Two fish of the same species must be this close to each other.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>())); BreedingMinutes = ((BaseUnityPlugin)this).Config.Bind<int>("Pond", "BreedingMinutes", 30, new ConfigDescription("Real elapsed minutes between births per species and pond.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 240), Array.Empty<object>())); MaxFishPerPond = ((BaseUnityPlugin)this).Config.Bind<int>("Pond", "MaxFishPerPond", 12, new ConfigDescription("Maximum number of nearby living fish of all species combined.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 40), Array.Empty<object>())); PreventWallEscape = ((BaseUnityPlugin)this).Config.Bind<bool>("Pond", "PreventWallEscape", true, "Softly steer unhooked fish away from nearby built walls; only rescue after a confirmed breach. Works for tracked fish while the area is loaded and the mod is running on the fish's network owner."); ContainmentInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Pond", "ContainmentIntervalSeconds", 0.5f, new ConfigDescription("Seconds between checking pond fish positions. Reduce cautiously.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 2f), Array.Empty<object>())); RegisterLocalizations(); PrefabManager.OnVanillaPrefabsAvailable += RegisterBasket; try { new Harmony("community.valheim.fishbreeding").PatchAll(typeof(FishBreedingPlugin).Assembly); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Basket interaction Harmony patch failed: " + ex)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Fish Breeding v0.1.7.2 loaded: basket icon, recipe, three languages, safe local fish pickup."); } internal static void LogBreedingInfo(string message) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)message); } } internal static void LogBreedingWarning(string message) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)message); } } private void RegisterBasket() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) try { GameObject val = LoadBasketVisual(); PieceConfig val2 = new PieceConfig { Name = "$piece_fbb_basket", Description = "$piece_fbb_basket_desc", PieceTable = PieceTables.Hammer, Category = PieceCategories.Misc }; val2.AddRequirement("FineWood", 20, true); val2.AddRequirement("Stone", 5, true); val2.AddRequirement("GreydwarfEye", 5, true); val2.AddRequirement("Root", 10, true); val2.AddRequirement("Thunderstone", 1, true); if ((Object)(object)val != (Object)null) { try { val2.Icon = RenderManager.Instance.Render(val, RenderManager.IsometricRotation); if ((Object)(object)val2.Icon == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Basket icon render returned null; check RenderManager in BepInEx log."); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Basket icon rendering failed: " + ex)); } } CustomPiece val3 = new CustomPiece("FishBreeding_PondMarker", "sign_notext", val2); if ((Object)(object)val != (Object)null) { Renderer[] componentsInChildren = val3.PiecePrefab.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } Collider[] componentsInChildren2 = val3.PiecePrefab.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { componentsInChildren2[i].enabled = false; } GameObject obj = Object.Instantiate<GameObject>(val, val3.PiecePrefab.transform, false); ((Object)obj).name = "FishBreedingBasket_Visual"; obj.transform.localPosition = Vector3.zero; obj.transform.localRotation = Quaternion.identity; obj.transform.localScale = Vector3.one; obj.SetActive(true); int num = LayerMask.NameToLayer("piece"); if (num < 0) { num = val3.PiecePrefab.layer; ((BaseUnityPlugin)this).Logger.LogWarning((object)("'piece' layer not found; falling back to sign prefab layer " + num)); } int num2 = 0; componentsInChildren2 = obj.GetComponentsInChildren<Collider>(true); foreach (Collider val4 in componentsInChildren2) { if (val4.enabled && !val4.isTrigger) { ((Component)val4).gameObject.layer = num; if ((Object)(object)((Component)val4).GetComponent<BasketColliderInteraction>() == (Object)null) { ((Component)val4).gameObject.AddComponent<BasketColliderInteraction>(); } num2++; } } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Fish Breeding Basket visuals attached from AssetBundle; interaction colliders: " + num2 + ", layer=" + num)); if (num2 == 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"No active non-trigger colliders on basket! E interaction will be unavailable."); } } else { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Basket AssetBundle unavailable; using original sign appearance."); } if ((Object)(object)val3.PiecePrefab == (Object)null) { throw new InvalidOperationException("Failed to clone vanilla sign_notext prefab."); } val3.PiecePrefab.AddComponent<FishPondMarker>(); if (!PieceManager.Instance.AddPiece(val3)) { throw new InvalidOperationException("Jotunn PieceManager did not accept the basket piece."); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Fish Breeding registered in Hammer menu (prefab id: FishBreeding_PondMarker)."); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not register Fish Breeding Basket: " + ex2)); } finally { PrefabManager.OnVanillaPrefabsAvailable -= RegisterBasket; } } private void RegisterLocalizations() { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "piece_fbb_basket", "Spawning Basket" }, { "piece_fbb_basket_desc", "A gift from Njörd, the Vanir god of the sea, winds, seafaring and fishing. Its ancient blue runes bless the waters with new life." }, { "piece_fbb_collect", "Collect fish" }, { "piece_fbb_no_extra", "No surplus fish to collect. Two of each species are kept." }, { "piece_fbb_not_owner", "This basket or some fish are owned by another player. Try again when you own this area." }, { "piece_fbb_collected", "Fish collection started: {0}. Two of each species remain." }, { "piece_fbb_no_room", "Inventory full or fish too heavy. Uncollected fish remain in the pond." } }); text = "German"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "piece_fbb_basket", "Laichkorb" }, { "piece_fbb_basket_desc", "Ein Geschenk Njörds, des Wanengottes des Meeres, der Winde, der Seefahrt und des Fischfangs. Die uralten blauen Runen des Korbes segnen die Gewässer mit neuem Leben." }, { "piece_fbb_collect", "Fische einsammeln" }, { "piece_fbb_no_extra", "Keine überschüssigen Fische. Von jeder Art bleiben zwei zurück." }, { "piece_fbb_not_owner", "Ein anderer Spieler besitzt diesen Laichkorb oder einige Fische. Versuche es erneut, wenn du Eigentümer dieses Bereichs bist." }, { "piece_fbb_collected", "Fische eingesammelt: {0}. Zwei jeder Art bleiben zurück." }, { "piece_fbb_no_room", "Inventar voll oder Fische zu schwer. Nicht eingesammelte Fische bleiben im Teich." } }); text = "Hungarian"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "piece_fbb_basket", "Ívatókosár" }, { "piece_fbb_basket_desc", "Njörd ajándéka, a ván istené, aki a tenger, a szelek, a hajózás és a halászat ura. A kosár ősi kék rúnái új élettel áldják meg a vizeket." }, { "piece_fbb_collect", "Halak begyűjtése" }, { "piece_fbb_no_extra", "Nincs begyűjthető szaporulat. Fajonként két hal marad." }, { "piece_fbb_not_owner", "A kosár vagy néhány hal más játékos tulajdonában van. Próbáld meg a terület tulajdonosaként." }, { "piece_fbb_collected", "Begyűjtés elindítva: {0} hal. Fajonként két hal marad." }, { "piece_fbb_no_room", "Tele az inventory, vagy a halak túl nehezek. A többi hal a tóban marad." } }); } private GameObject LoadBasketVisual() { string directoryName = Path.GetDirectoryName(typeof(FishBreedingPlugin).Assembly.Location); if (string.IsNullOrEmpty(directoryName)) { return null; } string text = Path.Combine(directoryName, "fishbreedingbasket"); if (!File.Exists(text)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Missing AssetBundle at " + text)); return null; } _basketBundle = AssetBundle.LoadFromFile(text); if ((Object)(object)_basketBundle == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("AssetBundle.LoadFromFile failed at " + text)); return null; } string[] allAssetNames = _basketBundle.GetAllAssetNames(); foreach (string text2 in allAssetNames) { if (text2.EndsWith("/fishbreedingbasket.prefab", StringComparison.OrdinalIgnoreCase) || text2.Equals("fishbreedingbasket.prefab", StringComparison.OrdinalIgnoreCase)) { GameObject val = _basketBundle.LoadAsset<GameObject>(text2); if ((Object)(object)val != (Object)null) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded basket prefab: " + text2)); return val; } } } ((BaseUnityPlugin)this).Logger.LogWarning((object)"Bundle loaded but FishBreedingBasket.prefab was not found."); return null; } } public sealed class FishPondMarker : MonoBehaviour { private sealed class FishInsideRecord { internal Fish Fish; internal Vector3 LastSafePosition; internal float LastRescueTime = -100f; } private static readonly List<FishPondMarker> ActivePonds = new List<FishPondMarker>(); private static readonly MethodInfo IsOutOfWaterMethod = AccessTools.Method(typeof(Fish), "IsOutOfWater", (Type[])null, (Type[])null); private static bool _warnedWaterCheck; private ZNetView _netView; private const float TickIntervalSeconds = 15f; private readonly Dictionary<int, FishInsideRecord> _fishInside = new Dictionary<int, FishInsideRecord>(); private readonly List<int> _removeRecords = new List<int>(); private static readonly MethodInfo FishIsHookedMethod = AccessTools.Method(typeof(Fish), "IsHooked", (Type[])null, (Type[])null); private static readonly FieldInfo FishWaypointField = AccessTools.Field(typeof(Fish), "m_waypoint"); private static bool _warnedWaypoint; private const float WallLookAheadMeters = 1.7f; private const float SafeCheckpointWallClearance = 0.85f; private const float RescueCooldownSeconds = 1.5f; private float _containmentTime; private void Awake() { _netView = ((Component)this).GetComponent<ZNetView>(); ActivePonds.Add(this); ((MonoBehaviour)this).InvokeRepeating("BreedingTick", Random.Range(7f, 11f), 15f); } private void OnDestroy() { ((MonoBehaviour)this).CancelInvoke("BreedingTick"); ActivePonds.Remove(this); _fishInside.Clear(); } private void Update() { if (FishBreedingPlugin.PreventWallEscape == null || !FishBreedingPlugin.PreventWallEscape.Value || FishBreedingPlugin.ModEnabled == null || !FishBreedingPlugin.ModEnabled.Value) { return; } _containmentTime += Time.deltaTime; if (_containmentTime < FishBreedingPlugin.ContainmentInterval.Value) { return; } _containmentTime = 0f; try { KeepFishBehindWalls(); } catch (Exception ex) { FishBreedingPlugin.LogBreedingWarning("Wall containment check failed: " + ex); } } private void KeepFishBehindWalls() { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0134: 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) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_netView == (Object)null || !_netView.IsValid() || (Object)(object)ZNetScene.instance == (Object)null) { return; } float value = FishBreedingPlugin.PondRadius.Value; float num = value * value; Fish[] array = Object.FindObjectsOfType<Fish>(); foreach (Fish val in array) { if ((Object)(object)val == (Object)null) { continue; } ZNetView component = ((Component)val).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { continue; } int instanceID = ((Object)val).GetInstanceID(); if (_fishInside.ContainsKey(instanceID)) { continue; } Vector3 position = ((Component)val).transform.position; if (HorizontalDistanceSq(position, ((Component)this).transform.position) > num || !BelongsToThisPond(position) || !IsSwimming(val) || HasBuiltWallBetween(PondReferenceAtHeight(position.y), position)) { continue; } Vector3 lastSafePosition = position; if (IsNearBuiltWall(position, 0.85f)) { Vector3 val2 = InwardTarget(position, 1f); if (!HasBuiltWallBetween(position, val2)) { lastSafePosition = val2; } } _fishInside.Add(instanceID, new FishInsideRecord { Fish = val, LastSafePosition = lastSafePosition }); } _removeRecords.Clear(); foreach (KeyValuePair<int, FishInsideRecord> item in _fishInside) { FishInsideRecord value2 = item.Value; Fish fish = value2.Fish; if ((Object)(object)fish == (Object)null) { _removeRecords.Add(item.Key); continue; } ZNetView component2 = ((Component)fish).GetComponent<ZNetView>(); if ((Object)(object)component2 == (Object)null || !component2.IsValid() || !component2.IsOwner()) { _removeRecords.Add(item.Key); continue; } if (IsHookedByPlayer(fish)) { _removeRecords.Add(item.Key); continue; } Vector3 position2 = ((Component)fish).transform.position; Vector3 lastSafePosition2 = value2.LastSafePosition; bool num2 = HasBuiltWallBetween(lastSafePosition2, position2); bool flag = HasBuiltWallBetween(PondReferenceAtHeight(lastSafePosition2.y), new Vector3(position2.x, lastSafePosition2.y, position2.z)); if (num2 || flag) { if (IsNearBuiltWall(position2, 0.6f)) { if (IsSwimming(fish)) { SteerInward(fish, position2, nearWall: true); } } else if (Time.time - value2.LastRescueTime >= 1.5f) { TeleportToSafeSide(fish, lastSafePosition2); value2.LastRescueTime = Time.time; SteerInward(fish, lastSafePosition2, nearWall: true); } continue; } float num3 = HorizontalDistanceSq(position2, ((Component)this).transform.position); if (num3 > num) { _removeRecords.Add(item.Key); } else if (IsSwimming(fish)) { Vector3 val3 = FishHeading(fish, position2); bool flag2 = IsWallAhead(position2, val3, 1.7f); bool flag3 = num3 > (value - 1.25f) * (value - 1.25f) && Vector3.Dot(val3, position2 - ((Component)this).transform.position) > 0f; if (flag2 || flag3) { SteerInward(fish, position2, flag2); } else if (num3 < (value - 0.75f) * (value - 0.75f) && !IsNearBuiltWall(position2, 0.85f)) { value2.LastSafePosition = position2; } } } foreach (int removeRecord in _removeRecords) { _fishInside.Remove(removeRecord); } } private Vector3 InwardTarget(Vector3 position, float meters) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)this).transform.position - position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.02f) { return position; } return position + ((Vector3)(ref val)).normalized * meters; } private static void TeleportToSafeSide(Fish fish, Vector3 safe) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) Rigidbody component = ((Component)fish).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { component.position = safe; component.velocity = Vector3.zero; component.angularVelocity = Vector3.zero; } ((Component)fish).transform.position = safe; } private void SteerInward(Fish fish, Vector3 position, bool nearWall) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) Vector3 val = InwardTarget(position, nearWall ? 3f : 2.2f); Vector3 val2 = val - position; if (((Vector3)(ref val2)).sqrMagnitude < 0.02f) { return; } if (FishWaypointField != null && FishWaypointField.FieldType == typeof(Vector3)) { try { FishWaypointField.SetValue(fish, val); } catch (Exception ex) { if (!_warnedWaypoint) { _warnedWaypoint = true; FishBreedingPlugin.LogBreedingWarning("Fish waypoint steering unavailable: " + ex.Message); } } } else if (!_warnedWaypoint) { _warnedWaypoint = true; FishBreedingPlugin.LogBreedingWarning("Fish.m_waypoint is missing or changed; using gentle velocity steering only."); } Rigidbody component = ((Component)fish).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { Vector3 val3 = val - position; val3.y = 0f; ((Vector3)(ref val3)).Normalize(); Vector3 velocity = component.velocity; Vector3 val4 = default(Vector3); ((Vector3)(ref val4))..ctor(velocity.x, 0f, velocity.z); float num = Mathf.Clamp(((Vector3)(ref val4)).magnitude, 0.5f, 1.3f); Vector3 val5 = Vector3.Lerp(val4, val3 * num, nearWall ? 0.55f : 0.25f); component.velocity = new Vector3(val5.x, velocity.y, val5.z); } } private static Vector3 FishHeading(Fish fish, Vector3 position) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) Rigidbody component = ((Component)fish).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { Vector3 velocity = component.velocity; velocity.y = 0f; if (((Vector3)(ref velocity)).sqrMagnitude > 0.03f) { return ((Vector3)(ref velocity)).normalized; } } if (FishWaypointField != null && FishWaypointField.FieldType == typeof(Vector3)) { try { Vector3 val = (Vector3)FishWaypointField.GetValue(fish) - position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > 0.05f) { return ((Vector3)(ref val)).normalized; } } catch { } } Vector3 forward = ((Component)fish).transform.forward; forward.y = 0f; if (!(((Vector3)(ref forward)).sqrMagnitude > 0.01f)) { return Vector3.zero; } return ((Vector3)(ref forward)).normalized; } private static bool IsWallAhead(Vector3 position, Vector3 heading, float meters) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (((Vector3)(ref heading)).sqrMagnitude < 0.01f) { return false; } RaycastHit[] array = Physics.SphereCastAll(position, 0.2f, heading, meters, -5, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val = array[i]; if (IsBuiltWallCollider(((RaycastHit)(ref val)).collider)) { return true; } } return false; } private static bool IsNearBuiltWall(Vector3 position, float meters) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Collider[] array = Physics.OverlapSphere(position, meters, -5, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { if (IsBuiltWallCollider(array[i])) { return true; } } return false; } private Vector3 PondReferenceAtHeight(float y) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) return new Vector3(((Component)this).transform.position.x, y, ((Component)this).transform.position.z); } private static float HorizontalDistanceSq(Vector3 a, Vector3 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = a.x - b.x; float num2 = a.z - b.z; return num * num + num2 * num2; } private static bool HasBuiltWallBetween(Vector3 from, Vector3 to) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) Vector3 val = to - from; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < 0.05f) { return false; } RaycastHit[] array = Physics.RaycastAll(from, val / magnitude, magnitude, -5, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val2 = array[i]; if (IsBuiltWallCollider(((RaycastHit)(ref val2)).collider)) { return true; } } return false; } private static bool IsBuiltWallCollider(Collider collider) { if ((Object)(object)collider == (Object)null) { return false; } Piece componentInParent = ((Component)collider).GetComponentInParent<Piece>(); if ((Object)(object)componentInParent == (Object)null) { return false; } string text = ((Object)((Component)componentInParent).gameObject).name.ToLowerInvariant(); if (!text.Contains("stone") && !text.Contains("grausten") && !text.Contains("blackmarble") && !text.Contains("woodwall")) { return text.Contains("wall_"); } return true; } private static bool IsHookedByPlayer(Fish fish) { if (FishIsHookedMethod == null) { return false; } try { return (bool)FishIsHookedMethod.Invoke(fish, null); } catch { return false; } } internal void CollectSurplus(Player player) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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_00f5: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || FishBreedingPlugin.ModEnabled == null || !FishBreedingPlugin.ModEnabled.Value || (Object)(object)_netView == (Object)null || !_netView.IsValid() || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return; } if (!_netView.IsOwner()) { TellPlayer(player, "$piece_fbb_not_owner"); return; } float value = FishBreedingPlugin.PondRadius.Value; float num = value * value; Dictionary<string, List<Fish>> dictionary = new Dictionary<string, List<Fish>>(StringComparer.Ordinal); Fish[] array = Object.FindObjectsOfType<Fish>(); foreach (Fish val in array) { if ((Object)(object)val == (Object)null || !IsSwimming(val) || IsHookedByPlayer(val)) { continue; } Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val2)).sqrMagnitude > num || !BelongsToThisPond(((Component)val).transform.position)) { continue; } string vanillaFishPrefabName = GetVanillaFishPrefabName(((Component)val).gameObject); if (vanillaFishPrefabName != null) { if (!dictionary.TryGetValue(vanillaFishPrefabName, out var value2)) { value2 = (dictionary[vanillaFishPrefabName] = new List<Fish>()); } value2.Add(val); } } int num2 = 0; bool flag = false; bool flag2 = false; Inventory inventory = ((Humanoid)player).GetInventory(); foreach (KeyValuePair<string, List<Fish>> item in dictionary) { if (item.Value.Count <= 2) { continue; } for (int j = 2; j < item.Value.Count; j++) { Fish val3 = item.Value[j]; if ((Object)(object)val3 == (Object)null) { continue; } ZNetView component = ((Component)val3).GetComponent<ZNetView>(); ItemDrop component2 = ((Component)val3).GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner() || (Object)(object)component2 == (Object)null || component2.m_itemData == null) { flag = true; } else if (!inventory.CanAddItem(component2.m_itemData, 1)) { flag2 = true; } else if (component2.CanPickup(true)) { try { component2.Pickup((Humanoid)(object)player); num2++; } catch (Exception ex) { FishBreedingPlugin.LogBreedingWarning("CollectSurplus pickup failed: " + ex); break; } } } } if (num2 > 0) { TellPlayer(player, string.Format(Localize("$piece_fbb_collected"), num2)); } else if (flag2) { TellPlayer(player, "$piece_fbb_no_room"); } else if (flag) { TellPlayer(player, "$piece_fbb_not_owner"); } else { TellPlayer(player, "$piece_fbb_no_extra"); } if (num2 > 0 && flag) { TellPlayer(player, "$piece_fbb_not_owner"); } if (num2 > 0 && flag2) { TellPlayer(player, "$piece_fbb_no_room"); } FishBreedingPlugin.LogBreedingInfo("Basket harvest: attempted native pickup of " + num2 + " fish."); } private static string Localize(string token) { return LocalizationManager.Instance.TryTranslate(token); } private static void TellPlayer(Player player, string tokenOrText) { ((Character)player).Message((MessageType)2, tokenOrText.StartsWith("$", StringComparison.Ordinal) ? Localize(tokenOrText) : tokenOrText, 0, (Sprite)null, false); } private void BreedingTick() { try { if (FishBreedingPlugin.ModEnabled.Value && !((Object)(object)_netView == (Object)null) && _netView.IsValid() && _netView.IsOwner() && !((Object)(object)ZNetScene.instance == (Object)null) && !((Object)(object)ZNet.instance == (Object)null)) { RunBreedingTick(); } } catch (Exception ex) { FishBreedingPlugin.LogBreedingWarning("Breeding tick failed: " + ex); } } private unsafe void RunBreedingTick() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = _netView.GetZDO(); if (zDO == null) { return; } float value = FishBreedingPlugin.PondRadius.Value; float value2 = FishBreedingPlugin.ParentMaxDistance.Value; float num = value * value; float num2 = value2 * value2; Dictionary<string, List<Fish>> dictionary = new Dictionary<string, List<Fish>>(StringComparer.Ordinal); int num3 = 0; Fish[] array = Object.FindObjectsOfType<Fish>(); Vector3 val2; foreach (Fish val in array) { if ((Object)(object)val == (Object)null) { continue; } val2 = ((Component)val).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val2)).sqrMagnitude > num || !BelongsToThisPond(((Component)val).transform.position) || !IsSwimming(val)) { continue; } string vanillaFishPrefabName = GetVanillaFishPrefabName(((Component)val).gameObject); if (vanillaFishPrefabName != null) { num3++; if (!dictionary.TryGetValue(vanillaFishPrefabName, out var value3)) { value3 = (dictionary[vanillaFishPrefabName] = new List<Fish>()); } value3.Add(val); } } if (num3 >= FishBreedingPlugin.MaxFishPerPond.Value) { return; } long ticks = ZNet.instance.GetTime().Ticks; long ticks2 = TimeSpan.FromMinutes(FishBreedingPlugin.BreedingMinutes.Value).Ticks; foreach (KeyValuePair<string, List<Fish>> item in dictionary) { if (item.Value.Count < 2) { continue; } Fish val3 = null; Fish val4 = null; List<Fish> value4 = item.Value; for (int j = 0; j < value4.Count; j++) { if (!((Object)(object)val3 == (Object)null)) { break; } for (int k = j + 1; k < value4.Count; k++) { val2 = ((Component)value4[j]).transform.position - ((Component)value4[k]).transform.position; if (((Vector3)(ref val2)).sqrMagnitude <= num2) { val3 = value4[j]; val4 = value4[k]; break; } } } if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null) { continue; } string text = "FishBreeding.LastBirth." + item.Key; long num4 = zDO.GetLong(text, 0L); if (num4 <= 0 || num4 > ticks) { zDO.Set(text, ticks); } else { if (ticks - num4 < ticks2) { continue; } GameObject prefab = ZNetScene.instance.GetPrefab(item.Key); if ((Object)(object)prefab == (Object)null) { continue; } Vector3 val5 = (((Component)val3).transform.position + ((Component)val4).transform.position) * 0.5f; val5 += new Vector3(Random.Range(-0.25f, 0.25f), 0f, Random.Range(-0.25f, 0.25f)); GameObject val6 = Object.Instantiate<GameObject>(prefab, val5, Quaternion.identity); if ((Object)(object)val6 != (Object)null) { int quality = RollVanillaFishQuality(item.Key); ItemDrop component = val6.GetComponent<ItemDrop>(); if ((Object)(object)component != (Object)null) { component.SetQuality(quality); } else { FishBreedingPlugin.LogBreedingWarning("New fish " + item.Key + " has no ItemDrop; quality could not be set."); } zDO.Set(text, ticks); string[] obj = new string[6] { "New ", item.Key, " (quality ", quality.ToString(), ") spawned in marked pond at ", null }; val2 = val5; obj[5] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString(); FishBreedingPlugin.LogBreedingInfo(string.Concat(obj)); break; } } } } private static int RollVanillaFishQuality(string species) { float num; switch (species) { case "Fish4_cave": return 1; default: num = 0.2f; break; case "Fish10": case "Fish11": num = 0.15f; break; } float num2 = num; int i; for (i = 1; i < 5; i++) { if (!(Random.value < num2)) { break; } } return i; } private bool BelongsToThisPond(Vector3 fishPosition) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) Vector3 val = fishPosition - ((Component)this).transform.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; float num = FishBreedingPlugin.PondRadius.Value * FishBreedingPlugin.PondRadius.Value; foreach (FishPondMarker activePond in ActivePonds) { if (!((Object)(object)activePond == (Object)null) && !((Object)(object)activePond == (Object)(object)this)) { val = fishPosition - ((Component)activePond).transform.position; float sqrMagnitude2 = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude2 < num && sqrMagnitude2 < sqrMagnitude) { return false; } } } return true; } private static bool IsSwimming(Fish fish) { if (IsOutOfWaterMethod == null) { if (!_warnedWaterCheck) { FishBreedingPlugin.LogBreedingWarning("Fish.IsOutOfWater not available in this Valheim version; breeding is disabled for safety until the mod is updated."); _warnedWaterCheck = true; } return false; } try { return !(bool)IsOutOfWaterMethod.Invoke(fish, null); } catch { return false; } } private static string GetVanillaFishPrefabName(GameObject fishObject) { string text = ((Object)fishObject).name; int num = text.IndexOf("(Clone)", StringComparison.Ordinal); if (num >= 0) { text = text.Substring(0, num); } text = text.Trim(); if (text == "Fish4_cave") { return text; } if (!text.StartsWith("Fish", StringComparison.Ordinal)) { return null; } if (int.TryParse(text.Substring(4), out var result) && result >= 1 && result <= 12) { return text; } return null; } } }