Decompiled source of FishBreedingBasket v0.1.8

BepInEx/plugins/FishBreeding/FishBreeding.dll

Decompiled 5 days ago
using 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;
		}
	}
}