Decompiled source of ChillFishing v1.2.2

BepInEx/Lenson-ChillFishing/ChillFishing.dll

Decompiled 20 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ChillFishing;

[BepInPlugin("Lenson.valheim.ChillFishing", "ChillFishing", "1.2.2")]
public class Mod : BaseUnityPlugin
{
	public const string Id = "Lenson.valheim.ChillFishing";

	public const string Title = "ChillFishing";

	public const string Ver = "1.2.2";

	public static ConfigEntry<bool> AnyBait;

	public static ConfigEntry<float> BiteChance;

	public static ConfigEntry<float> NibbleForce;

	public static ConfigEntry<bool> TugOn;

	public static ConfigEntry<float> TugTime;

	public static ConfigEntry<float> TugForce;

	public static ConfigEntry<float> TugStep;

	public static ConfigEntry<float> CatchRange;

	public static ConfigEntry<float> SwimRange;

	public static ConfigEntry<bool> FlatHook;

	public static ConfigEntry<float> HookChance;

	public static ConfigEntry<float> MinDepth;

	public static ConfigEntry<float> MaxDepth;

	public static ConfigEntry<bool> PullLimit;

	public static ConfigEntry<float> PullMax;

	public static ConfigEntry<float> PullDecay;

	public static ConfigEntry<bool> BiteLimit;

	public static ConfigEntry<int> BiteMax;

	public static ConfigEntry<bool> Species;

	public static ConfigEntry<float> BreakStep;

	public static ConfigEntry<float> EscapeStep;

	public static ConfigEntry<string> Weights;

	public static ConfigEntry<float> SpawnTick;

	public static ConfigEntry<float> SpawnRadius;

	public static ConfigEntry<int> SpawnCount;

	public static ConfigEntry<int> SpeciesMax;

	public static ConfigEntry<string> SpeciesCaps;

	public static ConfigEntry<float> OtherWeight;

	public static ConfigEntry<float> IdleSecs;

	public static ConfigEntry<float> DespawnSecs;

	public static ConfigEntry<bool> SnapDepth;

	public static ConfigEntry<bool> CalmWaves;

	public static ConfigEntry<float> WaveMult;

	public static ConfigEntry<float> WaveRadius;

	public static ConfigEntry<bool> BossGate;

	public static ConfigEntry<bool> Quiet;

	public static ConfigEntry<bool> KeepSit;

	public static ConfigEntry<bool> SitPoseOn;

	public static ConfigEntry<bool> AquaOn;

	internal static Dictionary<Biome, float> BiomeW;

	internal static Dictionary<string, int> CapMap;

	internal static readonly Biome[] BiomeOrder;

	internal static readonly (string key, Biome biome)[] BossKeys;

	private float _tick;

	private static void Migrate<T>(ConfigEntry<T> entry, T oldDefault, T newDefault)
	{
		if (EqualityComparer<T>.Default.Equals(entry.Value, oldDefault))
		{
			entry.Value = newDefault;
		}
	}

	private void Awake()
	{
		//IL_0594: Unknown result type (might be due to invalid IL or missing references)
		AnyBait = ((BaseUnityPlugin)this).Config.Bind<bool>("A_Bait", "IgnoreBaitFilter", true, "Any bait catches any fish.");
		BiteChance = ((BaseUnityPlugin)this).Config.Bind<float>("A_Bait", "RealBiteChance", 0.7f, "Chance (0-1) that a nibble is a real bite. Otherwise the game plays its own 'wrong bait' feedback (weak tug, no hookup) -- used here purely as a false-alarm cue, unrelated to bait.");
		NibbleForce = ((BaseUnityPlugin)this).Config.Bind<float>("A_Bait", "NibbleForceMultiplier", 1.6f, "Multiplier for FishingFloat.m_nibbleForce -- how hard the float jerks on the initial bite.");
		TugOn = ((BaseUnityPlugin)this).Config.Bind<bool>("A_Bait", "SustainedPullEnabled", true, "On a REAL bite, keep tugging the float down repeatedly for a short window instead of one instant jerk -- makes it look like the float is actually being pulled under.");
		TugTime = ((BaseUnityPlugin)this).Config.Bind<float>("A_Bait", "SustainedPullDuration", 0.4f, "Seconds after a real bite during which extra downward tugs are applied.");
		TugForce = ((BaseUnityPlugin)this).Config.Bind<float>("A_Bait", "SustainedPullForce", 3f, "Magnitude of each extra downward tug during the sustained-pull window.");
		TugStep = ((BaseUnityPlugin)this).Config.Bind<float>("A_Bait", "SustainedPullInterval", 0.08f, "Seconds between extra tugs during the sustained-pull window.");
		CatchRange = ((BaseUnityPlugin)this).Config.Bind<float>("B_Safety", "CatchRangeMultiplier", 1.5f, "Multiplier for the radius fish notice the float (FishingFloat.m_range). 1 = vanilla.");
		SwimRange = ((BaseUnityPlugin)this).Config.Bind<float>("B_Safety", "SwimRangeMultiplier", 1.5f, "Multiplier for how far fish roam from their spawn point (Fish.m_swimRange). 1 = vanilla.");
		FlatHook = ((BaseUnityPlugin)this).Config.Bind<bool>("B_Safety", "EqualizeBaseHookChance", true, "Give ALL fish species the same bite chance (Fish.m_baseHookChance), instead of vanilla per-species values. Rarity is controlled by spawn frequency, not bite chance.");
		HookChance = ((BaseUnityPlugin)this).Config.Bind<float>("B_Safety", "BaseHookChanceValue", 0.0875f, "Bite chance (0-1) applied to all species when EqualizeBaseHookChance is on. Vanilla default for most fish is 0.5; this is deliberately low so bites feel earned.");
		Migrate(HookChance, 0.175f, 0.0875f);
		MinDepth = ((BaseUnityPlugin)this).Config.Bind<float>("B_Safety", "MinDepthMultiplier", 1.8f, "Multiplier for Fish.m_minDepth -- how close to the surface a fish is willing to swim. Higher = fish stay further below the surface. Still capped by actual water depth at each point.");
		MaxDepth = ((BaseUnityPlugin)this).Config.Bind<float>("B_Safety", "MaxDepthMultiplier", 1.4f, "Multiplier for Fish.m_maxDepth -- how deep a fish is willing to go. 1 = vanilla.");
		PullLimit = ((BaseUnityPlugin)this).Config.Bind<bool>("G_Tension", "LimitContinuousPull", true, "Force the fish to struggle (Fish.Escape) once accumulated pull 'tension' hits the threshold. Tension rises while you pull and decays while you don't -- can't be bypassed by rapidly tapping the button instead of holding, and is independent of stamina.");
		PullMax = ((BaseUnityPlugin)this).Config.Bind<float>("G_Tension", "MaxContinuousPullSeconds", 3f, "Tension threshold, in seconds of equivalent continuous pulling, before a struggle is forced.");
		PullDecay = ((BaseUnityPlugin)this).Config.Bind<float>("G_Tension", "PullTensionDecayRate", 1f, "How fast tension decays while not pulling, relative to how fast it rises while pulling. 1 = releasing cancels pulling 1:1. Higher = easier to recover; lower = tension lingers.");
		BiteLimit = ((BaseUnityPlugin)this).Config.Bind<bool>("H_BiteCap", "LimitBitesPerFloat", true, "Stop a float from attracting new fish after it has already been bitten MaxBitesPerFloat times this cast. Forces recasting instead of endless nibbling on one spot.");
		BiteMax = ((BaseUnityPlugin)this).Config.Bind<int>("H_BiteCap", "MaxBitesPerFloat", 2, "Max bites (nibbles) allowed per single cast before the float stops attracting fish.");
		Species = ((BaseUnityPlugin)this).Config.Bind<bool>("I_Character", "EnableSpeciesCharacter", true, "Scale break-distance risk and struggle duration by the hooked fish's biome tier (Meadows..DeepNorth), applied at the moment of hooking (Fish.OnHooked).");
		BreakStep = ((BaseUnityPlugin)this).Config.Bind<float>("I_Character", "BreakDistanceTierReduction", 0.08f, "Fraction FishingFloat.m_breakDistance shrinks per biome tier step. Later biome = less slack before the line snaps if you overpull. Clamped to never go below 40% of the original.");
		EscapeStep = ((BaseUnityPlugin)this).Config.Bind<float>("I_Character", "EscapeDurationTierMultiplier", 0.15f, "Fraction Fish.m_escapeMin/m_escapeMax grows per biome tier step. Later biome = longer struggles.");
		Weights = ((BaseUnityPlugin)this).Config.Bind<string>("C_Spawn", "FishBiomeWeights", "Meadows:10;Ocean:9;BlackForest:6.5;Swamp:5;Mountain:7.6;Plains:5.6;Mistlands:3.2;AshLands:1.8;DeepNorth:1", "Base spawn chance (0-100) by fish's native biome. Format Biome:weight separated by ';' - decimal part with '.' or ',', both work. Later biome = lower value = rarer.");
		BossGate = ((BaseUnityPlugin)this).Config.Bind<bool>("J_Progression", "UseBossProgression", true, "Fish only become catchable once their native biome's boss is defeated in this world (Meadows/Ocean always available). Turn off to have every species catchable from the start.");
		Quiet = ((BaseUnityPlugin)this).Config.Bind<bool>("L_Messages", "QuietFishingMessages", true, "Hide the 'hooked', 'wrong bait' and 'lost the fish' on-screen messages during fishing -- only 'line broke' and the final catch message still show. Set false for vanilla message behavior.");
		KeepSit = ((BaseUnityPlugin)this).Config.Bind<bool>("N_Sitting", "KeepSittingWhileFishing", true, "Casting and reeling in (right mouse) with a fishing rod no longer makes you stand up while sitting (sit emote or chair). Moving, jumping or crouching still stands you up. Set false for vanilla behavior.");
		SitPoseOn = ((BaseUnityPlugin)this).Config.Bind<bool>("N_Sitting", "FixSitRodPose", true, "While sitting on a chair/bench with a fishing rod, hold the rod with both hands like when casting instead of resting the hands on the knees. Set false for vanilla pose.");
		AquaOn = ((BaseUnityPlugin)this).Config.Bind<bool>("M_Experimental", "EnableAquariumTest", true, "EXPERIMENTAL, not final content: registers a test 'Aquarium' build piece (1 Crystal) with a single-slot container and a decorative fish, assembled from vanilla meshes.");
		BiomeW = ParseW(Weights.Value);
		if (!BiomeW.ContainsKey((Biome)1))
		{
			ZLog.LogWarning((object)"[ChillFishing] Meadows is missing from FishBiomeWeights, check the .cfg.");
		}
		SpawnTick = ((BaseUnityPlugin)this).Config.Bind<float>("E_Independent", "IndependentSpawnTickInterval", 2f, "How often (seconds) to check active floats and roll for a new spawn near them.");
		SpawnRadius = ((BaseUnityPlugin)this).Config.Bind<float>("E_Independent", "IndependentSpawnRadius", 10f, "Radius (meters) around the float where the target fish count is maintained.");
		SpawnCount = ((BaseUnityPlugin)this).Config.Bind<int>("E_Independent", "IndependentSpawnTargetCount", 4, "Target fish count (all species combined) kept near one active float.");
		SpeciesMax = ((BaseUnityPlugin)this).Config.Bind<int>("E_Independent", "PerSpeciesMaxNearby", 1, "Cap on one species near a float at once, unless overridden in SpeciesCapOverrides.");
		SpeciesCaps = ((BaseUnityPlugin)this).Config.Bind<string>("E_Independent", "SpeciesCapOverrides", "Fish1:2;Fish2:2", "Per-prefab cap override, format Name:cap separated by ';'. Overrides PerSpeciesMaxNearby for specific species.");
		CapMap = ParseCaps(SpeciesCaps.Value);
		OtherWeight = ((BaseUnityPlugin)this).Config.Bind<float>("E_Independent", "UnclassifiedFishWeight", 2.4f, "Rarity weight for fish found outside the normal SpawnSystem (via ZNetScene) - their real biome is unknown, so rarity is set manually as one flat number for all of them.");
		IdleSecs = ((BaseUnityPlugin)this).Config.Bind<float>("E_Independent", "IndependentIdleDespawnSeconds", 30f, "Seconds WITHOUT an active float nearby before despawning fish this system spawned (if not caught and not hooked). Counted from the last time a float was nearby, not from creation.");
		DespawnSecs = ((BaseUnityPlugin)this).Config.Bind<float>("E_Independent", "IndependentDespawnAfterSeconds", 900f, "Emergency age cap (seconds) regardless of nearby float activity - just in case activity tracking breaks. Keep well above IndependentIdleDespawnSeconds; this is a safety net only.");
		SnapDepth = ((BaseUnityPlugin)this).Config.Bind<bool>("E_Independent", "SnapSpawnToDepth", true, "Spawn fish already at a random depth (within its own min/max depth range) instead of at the surface. Without this, newly spawned fish swim near the surface for a while before diving.");
		CalmWaves = ((BaseUnityPlugin)this).Config.Bind<bool>("F_Waves", "DampenWavesNearBase", true, "Dampen wave height (WaterVolume.CalcWave) within WaveDampenRadius of your bed's spawn point (Game.instance.GetPlayerProfile().GetCustomSpawnPoint()). Does not affect waves elsewhere, e.g. while sailing.");
		WaveRadius = ((BaseUnityPlugin)this).Config.Bind<float>("F_Waves", "WaveDampenRadius", 50f, "Radius (meters) around the bed spawn point where waves are dampened.");
		WaveMult = ((BaseUnityPlugin)this).Config.Bind<float>("F_Waves", "WaveHeightMultiplierNearBase", 0.05f, "Wave height multiplier in that radius. 1 = vanilla, 0 = perfectly flat. 0.05 default is near-calm, guaranteed not to flood the base.");
		new Harmony("Lenson.valheim.ChillFishing").PatchAll(Assembly.GetExecutingAssembly());
		((BaseUnityPlugin)this).Logger.LogInfo((object)"ChillFishing 1.2.2 loaded.");
	}

	private void Update()
	{
		Tension.Tick();
		Tug.Tick();
		_tick += Time.deltaTime;
		if (!(_tick < SpawnTick.Value))
		{
			_tick = 0f;
			Bites.Prune();
			Spawner.Tick();
		}
	}

	private static Dictionary<Biome, float> ParseW(string csv)
	{
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		Dictionary<Biome, float> dictionary = new Dictionary<Biome, float>();
		string[] array = csv.Split(new char[1] { ';' });
		for (int i = 0; i < array.Length; i++)
		{
			string[] array2 = array[i].Split(new char[1] { ':' });
			if (array2.Length == 2)
			{
				string s = array2[1].Trim().Replace(',', '.');
				if (Enum.TryParse<Biome>(array2[0].Trim(), ignoreCase: true, out Biome result) && float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
				{
					dictionary[result] = result2;
				}
			}
		}
		return dictionary;
	}

	private static Dictionary<string, int> ParseCaps(string csv)
	{
		Dictionary<string, int> dictionary = new Dictionary<string, int>();
		string[] array = csv.Split(new char[1] { ';' });
		for (int i = 0; i < array.Length; i++)
		{
			string[] array2 = array[i].Split(new char[1] { ':' });
			if (array2.Length == 2 && int.TryParse(array2[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				dictionary[array2[0].Trim()] = result;
			}
		}
		return dictionary;
	}

	static Mod()
	{
		Biome[] array = new Biome[9];
		RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
		BiomeOrder = (Biome[])(object)array;
		BossKeys = new(string, Biome)[7]
		{
			("defeated_eikthyr", (Biome)8),
			("defeated_gdking", (Biome)2),
			("defeated_bonemass", (Biome)4),
			("defeated_dragon", (Biome)16),
			("defeated_goblinking", (Biome)512),
			("defeated_queen", (Biome)32),
			("defeated_fader", (Biome)64)
		};
	}
}
[HarmonyPatch(typeof(Fish), "TestBate")]
internal static class BaitPatch
{
	[HarmonyPrefix]
	private static bool Prefix(Fish __instance, FishingFloat ff, ref bool __result)
	{
		if (!Mod.AnyBait.Value)
		{
			return true;
		}
		__result = Random.value < Mod.BiteChance.Value;
		return false;
	}
}
[HarmonyPatch(typeof(FishingFloat), "Awake")]
internal static class FloatPatch
{
	[HarmonyPostfix]
	private static void Postfix(FishingFloat __instance)
	{
		float value = Mod.CatchRange.Value;
		if (value != 1f)
		{
			__instance.m_range *= value;
		}
		float value2 = Mod.NibbleForce.Value;
		if (value2 != 1f)
		{
			__instance.m_nibbleForce *= value2;
		}
	}
}
[HarmonyPatch(typeof(FishingFloat), "Message", new Type[]
{
	typeof(string),
	typeof(bool)
})]
internal static class MsgPatch
{
	[HarmonyPrefix]
	private static bool Prefix(string msg)
	{
		if (!Mod.Quiet.Value)
		{
			return true;
		}
		if (string.IsNullOrEmpty(msg))
		{
			return true;
		}
		if (msg == "$msg_fishing_linebroke")
		{
			return true;
		}
		if (msg.StartsWith("$msg_fishing_catched", StringComparison.Ordinal))
		{
			return true;
		}
		return false;
	}
}
[HarmonyPatch(typeof(Fish), "Awake")]
internal static class FishPatch
{
	[HarmonyPostfix]
	private static void Postfix(Fish __instance)
	{
		float value = Mod.SwimRange.Value;
		if (value != 1f)
		{
			__instance.m_swimRange *= value;
		}
		if (Mod.FlatHook.Value)
		{
			__instance.m_baseHookChance = Mod.HookChance.Value;
		}
		float value2 = Mod.MinDepth.Value;
		float value3 = Mod.MaxDepth.Value;
		if (value2 != 1f)
		{
			__instance.m_minDepth *= value2;
		}
		if (value3 != 1f)
		{
			__instance.m_maxDepth *= value3;
		}
		if (__instance.m_minDepth > __instance.m_maxDepth - 0.1f)
		{
			__instance.m_minDepth = __instance.m_maxDepth - 0.1f;
		}
	}
}
[HarmonyPatch(typeof(SpawnSystem), "Awake")]
internal static class CatalogPatch
{
	private static readonly HashSet<SpawnData> s_patched = new HashSet<SpawnData>();

	internal static readonly Dictionary<GameObject, Biome> NativeBiome = new Dictionary<GameObject, Biome>();

	[HarmonyPostfix]
	private static void Postfix(SpawnSystem __instance)
	{
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		if (__instance.m_spawnLists == null)
		{
			return;
		}
		foreach (SpawnSystemList spawnList in __instance.m_spawnLists)
		{
			if (spawnList?.m_spawners == null)
			{
				continue;
			}
			foreach (SpawnData spawner in spawnList.m_spawners)
			{
				if (!((Object)(object)spawner?.m_prefab == (Object)null) && !s_patched.Contains(spawner) && !((Object)(object)spawner.m_prefab.GetComponent<Fish>() == (Object)null))
				{
					s_patched.Add(spawner);
					NativeBiome[spawner.m_prefab] = BiomeOf(spawner.m_biome);
				}
			}
		}
	}

	private static Biome BiomeOf(Biome mask)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: 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)
		Biome[] biomeOrder = Mod.BiomeOrder;
		foreach (Biome val in biomeOrder)
		{
			if ((mask & val) != 0)
			{
				return val;
			}
		}
		return (Biome)1;
	}
}
[HarmonyPatch(typeof(ZNetScene), "Awake")]
internal static class ExtraFishPatch
{
	private static bool s_scanned;

	private static readonly Dictionary<string, Biome> Known = new Dictionary<string, Biome> { 
	{
		"Fish4_cave",
		(Biome)4
	} };

	[HarmonyPostfix]
	private static void Postfix(ZNetScene __instance)
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: 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)
		if (s_scanned)
		{
			return;
		}
		s_scanned = true;
		foreach (string prefabName in __instance.GetPrefabNames())
		{
			GameObject prefab = __instance.GetPrefab(prefabName);
			if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab.GetComponent<Fish>() == (Object)null) && !CatalogPatch.NativeBiome.ContainsKey(prefab))
			{
				Biome value2;
				Biome value = (Biome)(Known.TryGetValue(((Object)prefab).name, out value2) ? ((int)value2) : 0);
				CatalogPatch.NativeBiome[prefab] = value;
			}
		}
	}
}
internal static class Spawner
{
	private static readonly Dictionary<Fish, float> s_near = new Dictionary<Fish, float>();

	public static void Tick()
	{
		Prune();
		List<Vector3> activeFloatCenters = Centers();
		Touch(activeFloatCenters);
		DespawnIdle();
		TopUp(activeFloatCenters);
	}

	private static List<Vector3> Centers()
	{
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		List<Vector3> list = new List<Vector3>();
		foreach (FishingFloat allInstance in FishingFloat.GetAllInstances())
		{
			if (!((Object)(object)allInstance == (Object)null))
			{
				ZNetView component = ((Component)allInstance).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner() && allInstance.IsInWater())
				{
					list.Add(((Component)allInstance).transform.position);
				}
			}
		}
		return list;
	}

	private static void Touch(List<Vector3> activeFloatCenters)
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		if (activeFloatCenters.Count == 0)
		{
			return;
		}
		float value = Mod.SpawnRadius.Value;
		Fish[] array = s_near.Keys.ToArray();
		foreach (Fish val in array)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			foreach (Vector3 activeFloatCenter in activeFloatCenters)
			{
				if (Vector3.Distance(((Component)val).transform.position, activeFloatCenter) <= value)
				{
					s_near[val] = Time.time;
					break;
				}
			}
		}
	}

	private static void TopUp(List<Vector3> activeFloatCenters)
	{
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		if (activeFloatCenters.Count == 0)
		{
			return;
		}
		List<(GameObject, float)> list = Candidates();
		if (list.Count == 0)
		{
			return;
		}
		float value = Mod.SpawnRadius.Value;
		int value2 = Mod.SpawnCount.Value;
		foreach (Vector3 activeFloatCenter in activeFloatCenters)
		{
			if (CountNear(activeFloatCenter, value) >= value2)
			{
				continue;
			}
			List<(GameObject, float)> list2 = new List<(GameObject, float)>();
			foreach (var item in list)
			{
				int num = Cap(item.Item1);
				if (CountOf(item.Item1) < num)
				{
					list2.Add(item);
				}
			}
			if (list2.Count == 0)
			{
				continue;
			}
			float num2 = 0f;
			foreach (var item2 in list2)
			{
				num2 += item2.Item2;
			}
			if (!(Random.Range(0f, 100f) > num2))
			{
				SpawnOne(activeFloatCenter, value, list2);
			}
		}
	}

	private static int Cap(GameObject prefab)
	{
		if (Mod.CapMap.TryGetValue(((Object)prefab).name, out var value))
		{
			return value;
		}
		return Mod.SpeciesMax.Value;
	}

	private static int CountOf(GameObject prefab)
	{
		string name = ((Object)prefab).name;
		int num = 0;
		foreach (KeyValuePair<Fish, float> item in s_near)
		{
			if ((Object)(object)item.Key != (Object)null && ((Object)((Component)item.Key).gameObject).name.StartsWith(name))
			{
				num++;
			}
		}
		return num;
	}

	private static HashSet<Biome> Unlocked()
	{
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		HashSet<Biome> hashSet = new HashSet<Biome>
		{
			(Biome)1,
			(Biome)256
		};
		if ((Object)(object)ZoneSystem.instance != (Object)null)
		{
			(string, Biome)[] bossKeys = Mod.BossKeys;
			for (int i = 0; i < bossKeys.Length; i++)
			{
				var (text, item) = bossKeys[i];
				if (ZoneSystem.instance.GetGlobalKey(text))
				{
					hashSet.Add(item);
				}
			}
		}
		return hashSet;
	}

	private static List<(GameObject prefab, float weight)> Candidates()
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		List<(GameObject, float)> list = new List<(GameObject, float)>();
		HashSet<Biome> hashSet = (Mod.BossGate.Value ? Unlocked() : null);
		foreach (KeyValuePair<GameObject, Biome> item in CatalogPatch.NativeBiome)
		{
			float value;
			if ((int)item.Value == 0)
			{
				value = Mod.OtherWeight.Value;
			}
			else if ((hashSet != null && !hashSet.Contains(item.Value)) || !Mod.BiomeW.TryGetValue(item.Value, out value))
			{
				continue;
			}
			if (value > 0f)
			{
				list.Add((item.Key, value));
			}
		}
		return list;
	}

	private static void SpawnOne(Vector3 center, float radius, List<(GameObject prefab, float weight)> candidates)
	{
		//IL_0011: 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_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: 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_0079: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Pick(candidates);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		Vector2 val2 = Random.insideUnitCircle * radius;
		Vector3 val3 = center + new Vector3(val2.x, 0f, val2.y);
		GameObject val4 = Object.Instantiate<GameObject>(val, val3, Quaternion.identity);
		Fish component = val4.GetComponent<Fish>();
		if ((Object)(object)component != (Object)null)
		{
			s_near[component] = Time.time;
			if (Mod.SnapDepth.Value)
			{
				Snap(val4, component, val3);
			}
		}
	}

	private static void Snap(GameObject go, Fish fish, Vector3 spawnPos)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: 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)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		WaterVolume val = null;
		float num = float.MaxValue;
		foreach (WaterVolume instance in WaterVolume.Instances)
		{
			Vector3 val2 = ((Component)instance).transform.position - spawnPos;
			float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
			if (sqrMagnitude < num)
			{
				num = sqrMagnitude;
				val = instance;
			}
		}
		if ((Object)(object)val == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null)
		{
			return;
		}
		float waterSurface = val.GetWaterSurface(spawnPos, 1f);
		float num2 = default(float);
		if (ZoneSystem.instance.GetSolidHeight(spawnPos, ref num2, 0))
		{
			float num3 = waterSurface - num2;
			float num4 = Mathf.Min(fish.m_maxDepth, num3 - fish.m_height);
			if (!(num4 <= fish.m_minDepth))
			{
				float num5 = Random.Range(fish.m_minDepth, num4);
				Vector3 position = go.transform.position;
				position.y = waterSurface - num5;
				go.transform.position = position;
			}
		}
	}

	private static GameObject Pick(List<(GameObject prefab, float weight)> candidates)
	{
		float num = 0f;
		foreach (var candidate in candidates)
		{
			num += candidate.weight;
		}
		if (num <= 0f)
		{
			return null;
		}
		float num2 = Random.Range(0f, num);
		float num3 = 0f;
		foreach (var candidate2 in candidates)
		{
			num3 += candidate2.weight;
			if (num2 <= num3)
			{
				return candidate2.prefab;
			}
		}
		return candidates[candidates.Count - 1].prefab;
	}

	private static int CountNear(Vector3 point, float radius)
	{
		//IL_002e: 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)
		int num = 0;
		foreach (IMonoUpdater instance in Fish.Instances)
		{
			Fish val = (Fish)(object)((instance is Fish) ? instance : null);
			if (val != null && (Object)(object)val != (Object)null && Vector3.Distance(((Component)val).transform.position, point) <= radius)
			{
				num++;
			}
		}
		return num;
	}

	private static void Prune()
	{
		List<Fish> list = null;
		foreach (KeyValuePair<Fish, float> item in s_near)
		{
			if ((Object)(object)item.Key == (Object)null)
			{
				(list ?? (list = new List<Fish>())).Add(item.Key);
			}
		}
		if (list == null)
		{
			return;
		}
		foreach (Fish item2 in list)
		{
			s_near.Remove(item2);
		}
	}

	private static void DespawnIdle()
	{
		float value = Mod.IdleSecs.Value;
		float value2 = Mod.DespawnSecs.Value;
		List<Fish> list = null;
		foreach (KeyValuePair<Fish, float> item in s_near)
		{
			Fish key = item.Key;
			if (!((Object)(object)key == (Object)null) && !key.IsHooked())
			{
				float num = Time.time - item.Value;
				if (num >= value || num >= value2)
				{
					(list ?? (list = new List<Fish>())).Add(key);
				}
			}
		}
		if (list == null)
		{
			return;
		}
		foreach (Fish item2 in list)
		{
			s_near.Remove(item2);
			ZNetView component = ((Component)item2).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid() && component.IsOwner())
			{
				component.Destroy();
			}
		}
	}
}
[HarmonyPatch(typeof(WaterVolume), "CalcWave", new Type[]
{
	typeof(Vector3),
	typeof(float),
	typeof(float),
	typeof(float),
	typeof(float)
})]
internal static class WavePatch
{
	[HarmonyPostfix]
	private static void Postfix(Vector3 worldPos, ref float __result)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		if (!Mod.CalmWaves.Value || (Object)(object)Game.instance == (Object)null)
		{
			return;
		}
		PlayerProfile playerProfile = Game.instance.GetPlayerProfile();
		if (playerProfile == null)
		{
			return;
		}
		Vector3 customSpawnPoint = playerProfile.GetCustomSpawnPoint();
		if (!(((Vector3)(ref customSpawnPoint)).sqrMagnitude < 1f))
		{
			float num = worldPos.x - customSpawnPoint.x;
			float num2 = worldPos.z - customSpawnPoint.z;
			float num3 = num * num + num2 * num2;
			float value = Mod.WaveRadius.Value;
			if (num3 <= value * value)
			{
				__result *= Mod.WaveMult.Value;
			}
		}
	}
}
internal static class Tension
{
	private static readonly Dictionary<FishingFloat, float> s_tension = new Dictionary<FishingFloat, float>();

	private static readonly MethodInfo s_escape = AccessTools.Method(typeof(Fish), "Escape", (Type[])null, (Type[])null);

	public static void Tick()
	{
		if (!Mod.PullLimit.Value || (Object)(object)Player.m_localPlayer == (Object)null || s_escape == null)
		{
			return;
		}
		float deltaTime = Time.deltaTime;
		float value = Mod.PullMax.Value;
		float value2 = Mod.PullDecay.Value;
		foreach (FishingFloat allInstance in FishingFloat.GetAllInstances())
		{
			if ((Object)(object)allInstance == (Object)null)
			{
				continue;
			}
			ZNetView component = ((Component)allInstance).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner())
			{
				continue;
			}
			Fish val = allInstance.GetCatch();
			if ((Object)(object)val == (Object)null)
			{
				s_tension.Remove(allInstance);
				continue;
			}
			bool flag = ((Character)Player.m_localPlayer).IsBlocking();
			s_tension.TryGetValue(allInstance, out var value3);
			value3 += (flag ? deltaTime : ((0f - deltaTime) * value2));
			value3 = Mathf.Clamp(value3, 0f, value);
			if (value3 >= value)
			{
				s_escape.Invoke(val, null);
				value3 = 0f;
			}
			s_tension[allInstance] = value3;
		}
	}
}
[HarmonyPatch(typeof(Fish), "FindFloat")]
internal static class FindFloatPatch
{
	[HarmonyPostfix]
	private static void Postfix(ref FishingFloat __result)
	{
		if (Mod.BiteLimit.Value && !((Object)(object)__result == (Object)null) && Bites.GetCount(__result) >= Mod.BiteMax.Value)
		{
			__result = null;
		}
	}
}
[HarmonyPatch(typeof(FishingFloat), "RPC_Nibble")]
internal static class NibblePatch
{
	[HarmonyPostfix]
	private static void Postfix(FishingFloat __instance, bool correctBait)
	{
		if (correctBait)
		{
			Bites.Increment(__instance);
			Tug.Register(__instance);
		}
	}
}
internal static class Bites
{
	private static readonly Dictionary<FishingFloat, int> s_count = new Dictionary<FishingFloat, int>();

	public static int GetCount(FishingFloat ff)
	{
		if (!s_count.TryGetValue(ff, out var value))
		{
			return 0;
		}
		return value;
	}

	public static void Increment(FishingFloat ff)
	{
		s_count[ff] = GetCount(ff) + 1;
	}

	public static void Prune()
	{
		List<FishingFloat> list = null;
		foreach (FishingFloat key in s_count.Keys)
		{
			if ((Object)(object)key == (Object)null)
			{
				(list ?? (list = new List<FishingFloat>())).Add(key);
			}
		}
		if (list == null)
		{
			return;
		}
		foreach (FishingFloat item in list)
		{
			s_count.Remove(item);
		}
	}
}
[HarmonyPatch(typeof(Fish), "OnHooked")]
internal static class HookPatch
{
	[HarmonyPostfix]
	private static void Postfix(Fish __instance, FishingFloat ff)
	{
		if (!((Object)(object)ff == (Object)null) && Mod.Species.Value)
		{
			int num = Tier(((Object)((Component)__instance).gameObject).name);
			if (num >= 0)
			{
				float num2 = Mathf.Max(0.4f, 1f - (float)num * Mod.BreakStep.Value);
				ff.m_breakDistance *= num2;
				float num3 = 1f + (float)num * Mod.EscapeStep.Value;
				__instance.m_escapeMin *= num3;
				__instance.m_escapeMax *= num3;
			}
		}
	}

	private static int Tier(string instanceName)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		foreach (KeyValuePair<GameObject, Biome> item in CatalogPatch.NativeBiome)
		{
			if (instanceName.StartsWith(((Object)item.Key).name))
			{
				if ((int)item.Value == 0)
				{
					return Mod.BiomeOrder.Length / 2;
				}
				int num = Array.IndexOf(Mod.BiomeOrder, item.Value);
				return (num >= 0) ? num : 0;
			}
		}
		return -1;
	}
}
internal static class Tug
{
	private static readonly Dictionary<FishingFloat, float> s_biteTime = new Dictionary<FishingFloat, float>();

	private static readonly Dictionary<FishingFloat, float> s_lastPulse = new Dictionary<FishingFloat, float>();

	public static void Register(FishingFloat ff)
	{
		s_biteTime[ff] = Time.time;
		s_lastPulse[ff] = 0f;
	}

	public static void Tick()
	{
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		if (!Mod.TugOn.Value || s_biteTime.Count == 0)
		{
			return;
		}
		float value = Mod.TugTime.Value;
		float value2 = Mod.TugStep.Value;
		float value3 = Mod.TugForce.Value;
		List<FishingFloat> list = null;
		foreach (KeyValuePair<FishingFloat, float> item in s_biteTime)
		{
			FishingFloat key = item.Key;
			if ((Object)(object)key == (Object)null)
			{
				(list ?? (list = new List<FishingFloat>())).Add(key);
			}
			else if (Time.time - item.Value >= value)
			{
				(list ?? (list = new List<FishingFloat>())).Add(key);
			}
			else if (!(Time.time - s_lastPulse[key] < value2))
			{
				s_lastPulse[key] = Time.time;
				Rigidbody component = ((Component)key).GetComponent<Rigidbody>();
				if ((Object)(object)component != (Object)null)
				{
					component.AddForce(Vector3.down * value3, (ForceMode)2);
				}
			}
		}
		if (list == null)
		{
			return;
		}
		foreach (FishingFloat item2 in list)
		{
			s_biteTime.Remove(item2);
			s_lastPulse.Remove(item2);
		}
	}
}
[HarmonyPatch(typeof(Player), "SetControls")]
internal static class SitControls
{
	internal struct State
	{
		public bool Keep;

		public bool Attack;

		public bool AttackHold;

		public bool Secondary;

		public bool SecondaryHold;
	}

	internal static bool Suppress;

	internal static bool BlockHeld;

	private static readonly FieldInfo s_attack = AccessTools.Field(typeof(Player), "m_attack");

	private static readonly FieldInfo s_attackHold = AccessTools.Field(typeof(Player), "m_attackHold");

	private static readonly FieldInfo s_secondaryAttack = AccessTools.Field(typeof(Player), "m_secondaryAttack");

	private static readonly FieldInfo s_secondaryAttackHold = AccessTools.Field(typeof(Player), "m_secondaryAttackHold");

	internal static bool HasRod(Player player)
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Invalid comparison between Unknown and I4
		ItemData rightItem = ((Humanoid)player).RightItem;
		if (rightItem != null)
		{
			return (int)rightItem.m_shared.m_animationState == 9;
		}
		return false;
	}

	[HarmonyPrefix]
	private static void Prefix(Player __instance, Vector3 movedir, bool attack, bool attackHold, bool secondaryAttack, bool secondaryAttackHold, bool block, bool blockHold, bool jump, bool crouch, out State __state)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		__state = default(State);
		Suppress = false;
		BlockHeld = blockHold;
		if (Mod.KeepSit.Value && ((Character)__instance).IsSitting() && ((Character)__instance).IsAttached() && !((Character)__instance).InBed() && __instance.GetDoodadController() == null && !(movedir != Vector3.zero || jump || crouch) && (attack || secondaryAttack || block || blockHold) && HasRod(__instance))
		{
			Suppress = true;
			__state = new State
			{
				Keep = true,
				Attack = attack,
				AttackHold = attackHold,
				Secondary = secondaryAttack,
				SecondaryHold = secondaryAttackHold
			};
		}
	}

	[HarmonyPostfix]
	private static void Postfix(Player __instance, State __state)
	{
		if (__state.Keep)
		{
			s_attack?.SetValue(__instance, __state.Attack);
			s_attackHold?.SetValue(__instance, __state.AttackHold);
			s_secondaryAttack?.SetValue(__instance, __state.Secondary);
			s_secondaryAttackHold?.SetValue(__instance, __state.SecondaryHold);
		}
	}

	[HarmonyFinalizer]
	private static void Finalizer()
	{
		Suppress = false;
	}
}
[HarmonyPatch(typeof(Player), "StopEmote")]
internal static class StopEmotePatch
{
	[HarmonyPrefix]
	private static bool Prefix()
	{
		return !SitControls.Suppress;
	}
}
[HarmonyPatch(typeof(Player), "AttachStop")]
internal static class AttachStopPatch
{
	[HarmonyPrefix]
	private static bool Prefix()
	{
		return !SitControls.Suppress;
	}
}
internal static class SitCast
{
	internal static bool Active;

	internal static bool ShouldAllow(Player p)
	{
		if (Mod.KeepSit.Value && (Object)(object)p == (Object)(object)Player.m_localPlayer && ((Character)p).IsSitting() && ((Character)p).IsAttached() && !((Character)p).InBed() && p.GetDoodadController() == null)
		{
			return SitControls.HasRod(p);
		}
		return false;
	}
}
[HarmonyPatch(typeof(Player), "UpdateAttackBowDraw")]
internal static class BowDrawPatch
{
	[HarmonyPrefix]
	private static void Prefix(Player __instance)
	{
		SitCast.Active = SitCast.ShouldAllow(__instance);
	}

	[HarmonyFinalizer]
	private static void Finalizer()
	{
		SitCast.Active = false;
	}
}
[HarmonyPatch(typeof(Player), "IsAttached")]
internal static class AttachedPatch
{
	[HarmonyPostfix]
	private static void Postfix(ref bool __result)
	{
		if (SitCast.Active)
		{
			__result = false;
		}
	}
}
[HarmonyPatch(typeof(Player), "CanMove")]
internal static class CanMovePatch
{
	[HarmonyPostfix]
	private static void Postfix(Player __instance, ref bool __result)
	{
		if (!(!SitCast.Active | __result))
		{
			__result = !((Character)__instance).IsTeleporting() && !((Character)__instance).InCutscene() && (!((Character)__instance).IsEncumbered() || ((Character)__instance).HaveStamina(0f)) && !((Character)__instance).IsStaggering();
		}
	}
}
[HarmonyPatch(typeof(Player), "Awake")]
internal static class SitPoseAwake
{
	[HarmonyPostfix]
	private static void Postfix(Player __instance)
	{
		if ((Object)(object)((Component)__instance).GetComponent<SitPose>() == (Object)null)
		{
			((Component)__instance).gameObject.AddComponent<SitPose>();
		}
	}
}
internal class SitPose : MonoBehaviour
{
	private const float Blend = 0.3f;

	private const float ReelBlend = 0.25f;

	private const float ReelLoop = 2.12f;

	private static readonly FieldInfo s_anim = AccessTools.Field(typeof(Character), "m_animator");

	private static readonly string[] BoneNames = new string[8] { "LeftShoulder", "LeftArm", "LeftForeArm", "LeftHand", "RightShoulder", "RightArm", "RightForeArm", "RightHand" };

	private static readonly Quaternion[] TargetPose = (Quaternion[])(object)new Quaternion[8]
	{
		new Quaternion(0.60956f, -0.35159f, 0.5562f, 0.44211f),
		new Quaternion(0.40192f, -0.29319f, -0.31296f, 0.80904f),
		new Quaternion(-0.23605f, -0.12938f, 0.41047f, -0.87124f),
		new Quaternion(0.1612f, -0.36115f, -0.11762f, -0.91091f),
		new Quaternion(0.70773f, 0.13784f, -0.43075f, 0.54274f),
		new Quaternion(0.27825f, 0.07322f, 0.1619f, 0.94393f),
		new Quaternion(-0.04898f, 0.36119f, -0.20315f, -0.90877f),
		new Quaternion(-0.0327f, 0.31684f, 0.37229f, -0.87175f)
	};

	private static readonly Quaternion[] ReelDelta = (Quaternion[])(object)new Quaternion[8]
	{
		new Quaternion(-0.03519f, -0.00388f, 0.07383f, 0.99664f),
		new Quaternion(-0.02239f, -0.07061f, -0.08532f, 0.9936f),
		new Quaternion(0.08756f, -0.01714f, -0.07066f, 0.9935f),
		new Quaternion(0.10644f, -0.00366f, -0.00977f, 0.99426f),
		new Quaternion(0f, 0f, -0f, 1f),
		new Quaternion(-0.03253f, -0.06487f, 0.03561f, 0.99673f),
		new Quaternion(-0.01948f, -0.05461f, 0.4642f, 0.88383f),
		new Quaternion(0.01559f, -0.02822f, -0.1346f, 0.99038f)
	};

	private static readonly Vector3[] ReelChair = (Vector3[])(object)new Vector3[6]
	{
		new Vector3(-1f, 0f, 0f),
		Vector3.zero,
		Vector3.zero,
		new Vector3(21f, -25f, 0f),
		new Vector3(24f, 27f, 0f),
		new Vector3(6f, 0f, 0f)
	};

	private static readonly Vector3[] ReelShip = (Vector3[])(object)new Vector3[6]
	{
		new Vector3(-29f, 0f, 0f),
		new Vector3(-2f, 0f, 0f),
		new Vector3(-4f, 0f, 0f),
		new Vector3(14f, 10f, 0f),
		new Vector3(27f, -5f, 0f),
		new Vector3(6f, 0f, 0f)
	};

	private static readonly Vector3[] Chair = (Vector3[])(object)new Vector3[6]
	{
		new Vector3(16f, 9f, 0f),
		new Vector3(13f, -22f, 0f),
		new Vector3(10f, -20f, 0f),
		new Vector3(27f, 6f, 0f),
		Vector3.zero,
		Vector3.zero
	};

	private static readonly Vector3[] Ship = (Vector3[])(object)new Vector3[6]
	{
		new Vector3(16f, 22f, 0f),
		new Vector3(39f, -40f, 30f),
		new Vector3(32f, 12f, 0f),
		new Vector3(37f, -5f, 0f),
		Vector3.zero,
		Vector3.zero
	};

	private static readonly int[] TBone = new int[6] { 5, 6, 7, 1, 2, 3 };

	private static readonly int[] AxFrom = new int[6] { 5, 6, 6, 1, 2, 2 };

	private static readonly int[] AxTo = new int[6] { 6, 7, 7, 2, 3, 3 };

	private Player _player;

	private Transform[] _bones;

	private Vector3[] _tweak = Chair;

	private Vector3[] _reelTweak = ReelChair;

	private float _weight;

	private float _reelWeight;

	private float _phase;

	private static float Profile(float phase)
	{
		float num = phase * 21f;
		if (num < 2f)
		{
			return 1f;
		}
		if (num < 16f)
		{
			return 1f - Mathf.SmoothStep(0f, 1f, (num - 2f) / 14f);
		}
		if (num < 17f)
		{
			return 0f;
		}
		return Mathf.SmoothStep(0f, 1f, (num - 17f) / 4f);
	}

	private void Awake()
	{
		_player = ((Component)this).GetComponent<Player>();
	}

	private void LateUpdate()
	{
		//IL_0151: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_0192: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_020e: 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)
		{
			return;
		}
		bool flag = Mod.SitPoseOn.Value && Applies(_player);
		if (flag)
		{
			bool flag2 = ((Character)_player).IsAttachedToShip();
			_tweak = (flag2 ? Ship : Chair);
			_reelTweak = (flag2 ? ReelShip : ReelChair);
		}
		_weight = Mathf.MoveTowards(_weight, flag ? 1f : 0f, Time.deltaTime / 0.3f);
		if (_weight <= 0f || (_bones == null && !FindBones()))
		{
			return;
		}
		bool flag3 = flag && SitControls.BlockHeld;
		if (flag3 && _reelWeight <= 0f)
		{
			_phase = 16f / 21f;
		}
		_reelWeight = Mathf.MoveTowards(_reelWeight, flag3 ? 1f : 0f, Time.deltaTime / 0.25f);
		_phase = (_phase + Time.deltaTime / 2.12f) % 1f;
		float num = Profile(_phase) * _reelWeight;
		for (int i = 0; i < _bones.Length; i++)
		{
			Quaternion val = TargetPose[i];
			if (num > 0f)
			{
				val *= Quaternion.Slerp(Quaternion.identity, ReelDelta[i], num);
			}
			_bones[i].localRotation = Quaternion.Slerp(_bones[i].localRotation, val, _weight);
		}
		for (int j = 0; j < _tweak.Length; j++)
		{
			Tweak(j, _tweak[j], _weight);
		}
		float num2 = _weight * num;
		if (num2 > 0f)
		{
			for (int k = 0; k < _reelTweak.Length; k++)
			{
				Tweak(k, _reelTweak[k], num2);
			}
		}
	}

	private void Tweak(int k, Vector3 v, float w)
	{
		//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_001a: 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)
		//IL_0028: 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_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_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: 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_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_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		if (!(v == Vector3.zero))
		{
			Transform transform = ((Component)_player).transform;
			Quaternion val = Quaternion.AngleAxis(v.y * w, transform.up) * Quaternion.AngleAxis((0f - v.x) * w, transform.right);
			Vector3 val2 = _bones[AxTo[k]].position - _bones[AxFrom[k]].position;
			if (((Vector3)(ref val2)).sqrMagnitude > 1E-08f)
			{
				val = Quaternion.AngleAxis(v.z * w, ((Vector3)(ref val2)).normalized) * val;
			}
			Transform val3 = _bones[TBone[k]];
			val3.rotation = val * val3.rotation;
		}
	}

	private static bool Applies(Player p)
	{
		if (((Character)p).IsSitting() && ((Character)p).IsAttached() && !((Character)p).InBed() && p.GetDoodadController() == null && !((Character)p).InAttack())
		{
			return SitControls.HasRod(p);
		}
		return false;
	}

	private bool FindBones()
	{
		Animator val = (Animator)((s_anim != null) ? /*isinst with value type is only supported in some contexts*/: null);
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		Transform[] array = (Transform[])(object)new Transform[BoneNames.Length];
		for (int i = 0; i < BoneNames.Length; i++)
		{
			array[i] = FindFirst(((Component)val).transform, BoneNames[i]);
			if ((Object)(object)array[i] == (Object)null)
			{
				return false;
			}
		}
		_bones = array;
		return true;
	}

	private static Transform FindFirst(Transform t, string name)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		foreach (Transform item in t)
		{
			Transform val = item;
			if (((Object)val).name == name)
			{
				return val;
			}
			Transform val2 = FindFirst(val, name);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2;
			}
		}
		return null;
	}
}
[HarmonyPatch(typeof(ZNetScene), "Awake")]
internal static class AquaSceneAwake
{
	[HarmonyPostfix]
	private static void Postfix(ZNetScene __instance)
	{
		if (!Mod.AquaOn.Value || (Object)(object)AquaBuilder.Root != (Object)null)
		{
			return;
		}
		try
		{
			AquaBuilder.BuildGeo(__instance);
		}
		catch (Exception ex)
		{
			ZLog.LogError((object)("[ChillFishing] Aquarium build failed (geometry stage): " + ex));
		}
	}
}
[HarmonyPatch(typeof(ObjectDB), "Awake")]
internal static class AquaDbAwake
{
	[HarmonyPostfix]
	private static void Postfix(ObjectDB __instance)
	{
		if (!Mod.AquaOn.Value || (Object)(object)AquaBuilder.Root == (Object)null || AquaBuilder.RecipeDone)
		{
			return;
		}
		try
		{
			AquaBuilder.AddRecipe(__instance);
			AquaBuilder.RecipeDone = true;
		}
		catch (Exception ex)
		{
			ZLog.LogError((object)("[ChillFishing] Aquarium build failed (recipe/hammer stage): " + ex));
		}
	}
}
internal static class AquaBuilder
{
	private class AquaWater : MonoBehaviour
	{
		public float SizeX;

		public float Level;

		public float SizeZ;
	}

	private class AquaFish : MonoBehaviour
	{
		public Vector3 Half = new Vector3(0.6f, 0.15f, 0.25f);

		private Vector3 _target;

		private float _speed;

		private float _turn;

		private float _pause;

		private void Awake()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.localPosition = RandPoint();
			((Component)this).transform.localRotation = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
			_speed = Random.Range(0.12f, 0.28f);
			_turn = Random.Range(60f, 160f);
			NewTarget();
		}

		private Vector3 RandPoint()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(Random.Range(0f - Half.x, Half.x), Random.Range(0f - Half.y, Half.y), Random.Range(0f - Half.z, Half.z));
		}

		private void NewTarget()
		{
			//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)
			_target = RandPoint();
			_pause = Time.time + Random.Range(0f, 1.5f);
		}

		private void Update()
		{
			//IL_000f: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			if (!(Time.time < _pause))
			{
				Vector3 val = _target - ((Component)this).transform.localPosition;
				if (((Vector3)(ref val)).magnitude < 0.03f)
				{
					NewTarget();
					return;
				}
				Quaternion val2 = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up);
				((Component)this).transform.localRotation = Quaternion.RotateTowards(((Component)this).transform.localRotation, val2, _turn * Time.deltaTime);
				Transform transform = ((Component)this).transform;
				transform.localPosition += ((Component)this).transform.localRotation * Vector3.forward * (_speed * Time.deltaTime);
			}
		}
	}

	private class AquaWatch : MonoBehaviour
	{
		private const float Poll = 0.5f;

		private Container _container;

		private string _last;

		private float _next;

		private void Awake()
		{
			_container = ((Component)this).GetComponent<Container>();
			_next = Time.time + 0.5f;
		}

		private void Update()
		{
			if (!(Time.time < _next))
			{
				_next = Time.time + 0.5f;
				Check();
			}
		}

		private void Check()
		{
			ZNetScene instance = ZNetScene.instance;
			Inventory val = (((Object)(object)_container != (Object)null) ? _container.GetInventory() : null);
			if ((Object)(object)instance == (Object)null || val == null)
			{
				return;
			}
			List<ItemData> allItems = val.GetAllItems();
			string text = ((allItems.Count > 0 && (Object)(object)allItems[0].m_dropPrefab != (Object)null) ? ((Object)allItems[0].m_dropPrefab).name : null);
			if (text == _last)
			{
				return;
			}
			_last = text;
			Transform val2 = ((Component)this).transform.Find("AquariumWater");
			AquaWater aquaWater = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<AquaWater>() : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)aquaWater == (Object)null)
			{
				ZLog.LogWarning((object)"[ChillFishing] Aquarium: content changed but AquaWater not found.");
				return;
			}
			string text2 = ((text != null) ? SpeciesFor(instance, text) : null);
			ZLog.Log((object)("[ChillFishing] Aquarium: slot item='" + (text ?? "(empty)") + "' -> species='" + (text2 ?? "(none)") + "'."));
			if (text2 != null)
			{
				AddFish(instance, val2, aquaWater.SizeX, aquaWater.Level, aquaWater.SizeZ, text2);
			}
			else
			{
				RemoveFish(val2);
			}
		}
	}

	internal static GameObject Root;

	internal static bool RecipeDone;

	private const string CrystalSrc = "crystal_wall_1x1";

	private const int GridSegs = 24;

	private const float FishScale = 0.7f;

	private const float FishMarginXZ = 0.15f;

	private const float FishMarginY = 0.08f;

	private static readonly string[] WaveHints = new string[10] { "wave", "wind", "choppy", "amplitude", "ripple", "distort", "height", "displace", "bump", "normal" };

	private const string TessProp = "_Tess";

	private const float TessMin = 1f;

	private const string WaterSrc = "piece_barber";

	private const string WaterMatHint = "water";

	private static void Tint(MeshRenderer renderer)
	{
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Expected O, but got Unknown
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)renderer == (Object)null)
		{
			return;
		}
		Material sharedMaterial = ((Renderer)renderer).sharedMaterial;
		if ((Object)(object)sharedMaterial == (Object)null)
		{
			return;
		}
		Color val = default(Color);
		((Color)(ref val))..ctor(0.2f, 0.45f, 0.55f, 0.6f);
		string[] obj = new string[6] { "_Color", "_BaseColor", "_TintColor", "_WaterColor", "_SurfaceColor", "_ShallowColor" };
		MaterialPropertyBlock val2 = new MaterialPropertyBlock();
		((Renderer)renderer).GetPropertyBlock(val2);
		bool flag = false;
		string[] array = obj;
		foreach (string text in array)
		{
			if (sharedMaterial.HasProperty(text))
			{
				val2.SetColor(text, val);
				flag = true;
			}
		}
		if (flag)
		{
			((Renderer)renderer).SetPropertyBlock(val2);
		}
		else
		{
			ZLog.LogWarning((object)"[ChillFishing] Aquarium: water shader exposes none of the known color property names -- no tint applied.");
		}
	}

	private static Mesh SurfaceMesh(float width, float depth, int segmentsX, int segmentsZ)
	{
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: 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_00b1: 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_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: 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_018d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Expected O, but got Unknown
		segmentsX = Mathf.Max(1, segmentsX);
		segmentsZ = Mathf.Max(1, segmentsZ);
		int num = segmentsX + 1;
		int num2 = segmentsZ + 1;
		Vector3[] array = (Vector3[])(object)new Vector3[num * num2];
		Vector3[] array2 = (Vector3[])(object)new Vector3[array.Length];
		Vector2[] array3 = (Vector2[])(object)new Vector2[array.Length];
		Color[] array4 = (Color[])(object)new Color[array.Length];
		float num3 = width * 0.5f;
		float num4 = depth * 0.5f;
		for (int i = 0; i < num2; i++)
		{
			float num5 = (float)i / (float)segmentsZ;
			for (int j = 0; j < num; j++)
			{
				float num6 = (float)j / (float)segmentsX;
				int num7 = i * num + j;
				array[num7] = new Vector3(0f - num3 + num6 * width, 0f, 0f - num4 + num5 * depth);
				array2[num7] = Vector3.up;
				array3[num7] = new Vector2(num6, num5);
				array4[num7] = Color.white;
			}
		}
		int[] array5 = new int[segmentsX * segmentsZ * 6];
		int num8 = 0;
		for (int k = 0; k < segmentsZ; k++)
		{
			for (int l = 0; l < segmentsX; l++)
			{
				int num9 = k * num + l;
				int num10 = num9 + 1;
				int num11 = num9 + num;
				int num12 = num11 + 1;
				array5[num8++] = num9;
				array5[num8++] = num10;
				array5[num8++] = num11;
				array5[num8++] = num10;
				array5[num8++] = num12;
				array5[num8++] = num11;
			}
		}
		Mesh val = new Mesh
		{
			name = "AquariumWaterSurfaceGrid",
			vertices = array,
			normals = array2,
			uv = array3,
			colors = array4,
			triangles = array5
		};
		val.RecalculateBounds();
		val.RecalculateTangents();
		return val;
	}

	private static void BoxFace(Transform parent, Vector3 localCenter, Vector3 outwardNormal, float faceWidth, float faceHeight, int segments, Material[] materials, List<MeshRenderer> collectRenderers)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: 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_001d: 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)
		//IL_0029: 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_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("BodyFace");
		val.transform.SetParent(parent, false);
		val.transform.localPosition = localCenter;
		val.transform.localRotation = Quaternion.FromToRotation(Vector3.up, outwardNormal);
		MeshFilter obj = val.AddComponent<MeshFilter>();
		Mesh val2 = SurfaceMesh(faceWidth, faceHeight, segments, segments);
		DoubleSided(val2);
		obj.sharedMesh = val2;
		MeshRenderer val3 = val.AddComponent<MeshRenderer>();
		if (materials != null)
		{
			((Renderer)val3).sharedMaterials = materials;
		}
		collectRenderers?.Add(val3);
	}

	private static void DoubleSided(Mesh mesh)
	{
		int[] triangles = mesh.triangles;
		int[] array = new int[triangles.Length * 2];
		Array.Copy(triangles, array, triangles.Length);
		for (int i = 0; i < triangles.Length; i += 3)
		{
			array[triangles.Length + i] = triangles[i];
			array[triangles.Length + i + 1] = triangles[i + 2];
			array[triangles.Length + i + 2] = triangles[i + 1];
		}
		mesh.triangles = array;
	}

	private static List<MeshRenderer> SubBox(Transform parent, float width, float height, float depth, int segments, Material[] materials)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: 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_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)
		List<MeshRenderer> list = new List<MeshRenderer>();
		float num = width * 0.5f;
		float num2 = height * 0.5f;
		float num3 = depth * 0.5f;
		BoxFace(parent, new Vector3(0f, num2, 0f), Vector3.up, width, depth, segments, materials, list);
		BoxFace(parent, new Vector3(0f, 0f - num2, 0f), Vector3.down, width, depth, segments, materials, list);
		BoxFace(parent, new Vector3(num, 0f, 0f), Vector3.right, height, depth, segments, materials, list);
		BoxFace(parent, new Vector3(0f - num, 0f, 0f), Vector3.left, height, depth, segments, materials, list);
		BoxFace(parent, new Vector3(0f, 0f, num3), Vector3.forward, width, height, segments, materials, list);
		BoxFace(parent, new Vector3(0f, 0f, 0f - num3), Vector3.back, width, height, segments, materials, list);
		return list;
	}

	private static void Flatten(Renderer renderer, string label)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Expected O, but got Unknown
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Invalid comparison between Unknown and I4
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Invalid comparison between Unknown and I4
		if ((Object)(object)renderer == (Object)null)
		{
			return;
		}
		Material sharedMaterial = renderer.sharedMaterial;
		if ((Object)(object)sharedMaterial == (Object)null || (Object)(object)sharedMaterial.shader == (Object)null)
		{
			return;
		}
		Shader shader = sharedMaterial.shader;
		int propertyCount = shader.GetPropertyCount();
		MaterialPropertyBlock val = new MaterialPropertyBlock();
		renderer.GetPropertyBlock(val);
		bool flag = false;
		for (int i = 0; i < propertyCount; i++)
		{
			ShaderPropertyType propertyType = shader.GetPropertyType(i);
			if ((int)propertyType != 2 && (int)propertyType != 3)
			{
				continue;
			}
			string propertyName = shader.GetPropertyName(i);
			string text = propertyName.ToLowerInvariant();
			if (propertyName == "_Tess")
			{
				val.SetFloat(propertyName, 1f);
				flag = true;
				continue;
			}
			bool flag2 = false;
			string[] waveHints = WaveHints;
			foreach (string value in waveHints)
			{
				if (text.Contains(value))
				{
					flag2 = true;
					break;
				}
			}
			if (flag2)
			{
				val.SetFloat(propertyName, 0f);
				flag = true;
			}
		}
		if (flag)
		{
			renderer.SetPropertyBlock(val);
		}
		else
		{
			ZLog.LogWarning((object)("[ChillFishing] Aquarium: " + label + " -- no wave/ripple-like shader property found to flatten."));
		}
	}

	private static Material FindMat(ZNetScene scene, string prefabName, string nameContainsLower)
	{
		GameObject prefab = scene.GetPrefab(prefabName);
		if ((Object)(object)prefab == (Object)null)
		{
			return null;
		}
		Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Material[] sharedMaterials = componentsInChildren[i].sharedMaterials;
			if (sharedMaterials == null)
			{
				continue;
			}
			Material[] array = sharedMaterials;
			foreach (Material val in array)
			{
				if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name) && ((Object)val).name.ToLowerInvariant().Contains(nameContainsLower))
				{
					return val;
				}
			}
		}
		return null;
	}

	private static Material[] PrefabMats(ZNetScene scene, string prefabName)
	{
		if (string.IsNullOrEmpty(prefabName))
		{
			return null;
		}
		GameObject prefab = scene.GetPrefab(prefabName);
		if ((Object)(object)prefab == (Object)null)
		{
			return null;
		}
		Renderer componentInChildren = prefab.GetComponentInChildren<Renderer>();
		if ((Object)(object)componentInChildren == (Object)null || componentInChildren.sharedMaterials == null || componentInChildren.sharedMaterials.Length == 0)
		{
			return null;
		}
		return componentInChildren.sharedMaterials;
	}

	private static GameObject ClonePanel(ZNetScene scene, string sourcePrefabName, Vector3 targetSize, Vector3 localPos, Quaternion localRot, Transform parent)
	{
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: 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_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: 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_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_018f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_019d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e1: Expected O, but got Unknown
		GameObject prefab = scene.GetPrefab(sourcePrefabName);
		if ((Object)(object)prefab == (Object)null)
		{
			ZLog.LogWarning((object)("[ChillFishing] Aquarium: source prefab '" + sourcePrefabName + "' not found, skipping panel."));
			return null;
		}
		MeshFilter componentInChildren = prefab.GetComponentInChildren<MeshFilter>();
		MeshRenderer componentInChildren2 = prefab.GetComponentInChildren<MeshRenderer>();
		if ((Object)(object)componentInChildren == (Object)null || (Object)(object)componentInChildren2 == (Object)null || (Object)(object)componentInChildren.sharedMesh == (Object)null)
		{
			ZLog.LogWarning((object)("[ChillFishing] Aquarium: '" + sourcePrefabName + "' has no usable mesh, skipping panel."));
			return null;
		}
		GameObject val = new GameObject("Panel_" + sourcePrefabName);
		val.transform.SetParent(parent, false);
		val.transform.localPosition = localPos;
		val.transform.localRotation = localRot;
		MeshFilter val2 = val.AddComponent<MeshFilter>();
		val2.sharedMesh = componentInChildren.sharedMesh;
		Material[] sharedMaterials = ((Renderer)componentInChildren2).sharedMaterials;
		GameObject prefab2 = scene.GetPrefab("crystal_wall_1x1");
		MeshRenderer val3 = (((Object)(object)prefab2 != (Object)null) ? prefab2.GetComponentInChildren<MeshRenderer>() : null);
		if ((Object)(object)val3 != (Object)null && ((Renderer)val3).sharedMaterials.Length != 0)
		{
			sharedMaterials = ((Renderer)val3).sharedMaterials;
		}
		else
		{
			ZLog.LogWarning((object)"[ChillFishing] Aquarium: crystal material prefab 'crystal_wall_1x1' not found or has no material -- keeping stone material for now.");
		}
		((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterials = sharedMaterials;
		Bounds bounds = val2.sharedMesh.bounds;
		Vector3 size = ((Bounds)(ref bounds)).size;
		val.transform.localScale = new Vector3((size.x > 0.0001f) ? (targetSize.x / size.x) : 1f, (size.y > 0.0001f) ? (targetSize.y / size.y) : 1f, (size.z > 0.0001f) ? (targetSize.z / size.z) : 1f);
		BoxCollider obj = val.AddComponent<BoxCollider>();
		bounds = val2.sharedMesh.bounds;
		obj.center = ((Bounds)(ref bounds)).center;
		bounds = val2.sharedMesh.bounds;
		obj.size = ((Bounds)(ref bounds)).size;
		return val;
	}

	private static void AddWater(ZNetScene scene, Transform parent, float floorTopY, float surfaceY, float innerWidthX, float innerDepthZ)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Expected O, but got Unknown
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_018f: 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)
		float num = surfaceY - floorTopY;
		if (num <= 0f)
		{
			ZLog.LogWarning((object)"[ChillFishing] Aquarium: surfaceY <= floorTopY, skipping water.");
			return;
		}
		GameObject val = new GameObject("AquariumWater");
		val.transform.SetParent(parent, false);
		val.transform.localPosition = new Vector3(0f, floorTopY + num * 0.5f, 0f);
		BoxCollider obj = val.AddComponent<BoxCollider>();
		((Collider)obj).isTrigger = true;
		obj.size = new Vector3(innerWidthX, num, innerDepthZ);
		Material val2 = FindMat(scene, "piece_barber", "water");
		Material[] array = (Material[])((!((Object)(object)val2 != (Object)null)) ? ((Array)PrefabMats(scene, "crystal_wall_1x1")) : ((Array)new Material[1] { val2 }));
		GameObject val3 = new GameObject("WaterBody");
		val3.transform.SetParent(val.transform, false);
		val3.transform.localPosition = Vector3.zero;
		List<MeshRenderer> list = SubBox(val3.transform, innerWidthX, num * 0.98f, innerDepthZ, 24, array);
		if (array != null)
		{
			foreach (MeshRenderer item in list)
			{
				Tint(item);
				if ((Object)(object)val2 != (Object)null)
				{
					Flatten((Renderer)(object)item, "water body face");
				}
			}
		}
		else
		{
			ZLog.LogWarning((object)"[ChillFishing] Aquarium: no material found (barber water, mist or crystal) for water body.");
		}
		GameObject val4 = new GameObject("WaterSurface");
		val4.transform.SetParent(val.transform, false);
		val4.transform.localPosition = new Vector3(0f, num * 0.5f, 0f);
		val4.transform.localRotation = Quaternion.identity;
		val4.transform.localScale = Vector3.one;
		val4.AddComponent<MeshFilter>().sharedMesh = SurfaceMesh(innerWidthX, innerDepthZ, 24, 24);
		MeshRenderer val5 = val4.AddComponent<MeshRenderer>();
		Material[] array2 = (Material[])((!((Object)(object)val2 != (Object)null)) ? ((Array)PrefabMats(scene, "crystal_wall_1x1")) : ((Array)new Material[1] { val2 }));
		if (array2 != null)
		{
			((Renderer)val5).sharedMaterials = array2;
			if ((Object)(object)val2 != (Object)null)
			{
				Flatten((Renderer)(object)val5, "water surface");
			}
		}
		else
		{
			ZLog.LogWarning((object)"[ChillFishing] Aquarium: no material found (barber water, ice or crystal) for water surface.");
		}
		Tint(val5);
		WaterVolume val6 = val.AddComponent<WaterVolume>();
		val6.m_waterSurface = val5;
		val6.m_useGlobalWind = false;
		val6.m_forceDepth = num;
		val6.m_surfaceOffset = 0f;
		WaterVolume.Instances.Remove(val6);
		AquaWater aquaWater = val.AddComponent<AquaWater>();
		aquaWater.SizeX = innerWidthX;
		aquaWater.Level = num;
		aquaWater.SizeZ = innerDepthZ;
	}

	private static void RemoveFish(Transform waterParent)
	{
		Transform val = waterParent.Find("AquariumFish");
		if ((Object)(object)val != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)val).gameObject);
		}
	}

	private static void AddFish(ZNetScene scene, Transform waterParent, float innerWidthX, float waterHeight, float innerDepthZ, string speciesPrefabName)
	{
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Expected O, but got Unknown
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: 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_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_00c9: 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_00e5: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: 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_0111: 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_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0144: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		GameObject prefab = scene.GetPrefab(speciesPrefabName);
		if ((Object)(object)prefab == (Object)null)
		{
			ZLog.LogWarning((object)("[ChillFishing] Aquarium: fish prefab '" + speciesPrefabName + "' not found, skipping fish."));
			return;
		}
		MeshFilter componentInChildren = prefab.GetComponentInChildren<MeshFilter>();
		MeshRenderer componentInChildren2 = prefab.GetComponentInChildren<MeshRenderer>();
		if ((Object)(object)componentInChildren == (Object)null || (Object)(object)componentInChildren2 == (Object)null || (Object)(object)componentInChildren.sharedMesh == (Object)null)
		{
			ZLog.LogWarning((object)("[ChillFishing] Aquarium: '" + speciesPrefabName + "' has no usable mesh, skipping fish."));
			return;
		}
		RemoveFish(waterParent);
		GameObject val = new GameObject("AquariumFish");
		val.transform.SetParent(waterParent, false);
		GameObject val2 = new GameObject("Model");
		val2.transform.SetParent(val.transform, false);
		val2.transform.localPosition = prefab.transform.InverseTransformPoint(((Component)componentInChildren).transform.position);
		val2.transform.localRotation = Quaternion.Inverse(prefab.transform.rotation) * ((Component)componentInChildren).transform.rotation;
		Vector3 val3 = ((Component)componentInChildren).transform.lossyScale * 0.7f;
		val2.transform.localScale = val3;
		val2.AddComponent<MeshFilter>().sharedMesh = componentInChildren.sharedMesh;
		((Renderer)val2.AddComponent<MeshRenderer>()).sharedMaterials = ((Renderer)componentInChildren2).sharedMaterials;
		Bounds bounds = componentInChildren.sharedMesh.bounds;
		Vector3 val4 = Vector3.Scale(((Bounds)(ref bounds)).size, val3);
		float num = Mathf.Max(val4.x, val4.z) * 0.5f;
		float num2 = val4.y * 0.5f;
		Vector3 half = default(Vector3);
		((Vector3)(ref half))..ctor(Mathf.Max(0.02f, innerWidthX * 0.5f - 0.15f - num), Mathf.Max(0.01f, waterHeight * 0.5f - 0.08f - num2), Mathf.Max(0.02f, innerDepthZ * 0.5f - 0.15f - num));
		val.AddComponent<AquaFish>().Half = half;
	}

	private static string SpeciesFor(ZNetScene scene, string itemPrefabName)
	{
		GameObject prefab = scene.GetPrefab(itemPrefabName);
		if (!((Object)(object)prefab != (Object)null) || !((Object)(object)prefab.GetComponent<Fish>() != (Object)null))
		{
			return null;
		}
		return itemPrefabName;
	}

	public static void BuildGeo(ZNetScene scene)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: 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_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: 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_011a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		//IL_01af: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c8: 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_025a: Unknown result type (might be due to invalid IL or missing references)
		//IL_025f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("CF_AquariumTest");
		Object.DontDestroyOnLoad((Object)(object)val);
		ClonePanel(scene, "stone_wall_2x1", new Vector3(3f, 1.35f, 0.225f), new Vector3(0f, 0.675f, 0.7125f), Quaternion.identity, val.transform);
		ClonePanel(scene, "stone_wall_2x1", new Vector3(3f, 1.35f, 0.225f), new Vector3(0f, 0.675f, -0.7125f), Quaternion.identity, val.transform);
		ClonePanel(scene, "stone_wall_1x1", new Vector3(1.5f, 1.35f, 0.225f), new Vector3(1.4625f, 0.675f, 0f), Quaternion.Euler(0f, 90f, 0f), val.transform);
		ClonePanel(scene, "stone_wall_1x1", new Vector3(1.5f, 1.35f, 0.225f), new Vector3(-1.4625f, 0.675f, 0f), Quaternion.Euler(0f, 90f, 0f), val.transform);
		ClonePanel(scene, "stone_floor_2x2", new Vector3(3f, 1.5f, 0.15f), new Vector3(0f, 0.075f, 0f), Quaternion.Euler(90f, 0f, 0f), val.transform);
		AddWater(scene, val.transform, 0.15f, 0.975f, 2.775f, 1.275f);
		BoxCollider obj = val.AddComponent<BoxCollider>();
		obj.center = new Vector3(0f, 0.675f, 0f);
		obj.size = new Vector3(3f, 1.35f, 1.5f);
		ZNetView.StartGhostInit();
		ZNetView obj2 = val.AddComponent<ZNetView>();
		ZNetView.FinishGhostInit();
		obj2.m_persistent = true;
		ZSyncTransform obj3 = val.AddComponent<ZSyncTransform>();
		obj3.m_syncPosition = true;
		obj3.m_syncRotation = true;
		Piece obj4 = val.AddComponent<Piece>();
		obj4.m_name = "Aquarium";
		obj4.m_description = "Holds a single fish.";
		obj4.m_category = (PieceCategory)0;
		obj4.m_groundPiece = false;
		GameObject prefab = scene.GetPrefab("piece_workbench");
		WearNTear val2 = ((prefab != null) ? prefab.GetComponent<WearNTear>() : null);
		WearNTear val3 = val.AddComponent<WearNTear>();
		if ((Object)(object)val2 != (Object)null)
		{
			val3.m_health = val2.m_health;
			val3.m_materialType = val2.m_materialType;
			val3.m_noSupportWear = val2.m_noSupportWear;
			val3.m_noRoofWear = val2.m_noRoofWear;
			val3.m_supports = val2.m_supports;
			val3.m_burnable = val2.m_burnable;
			val3.m_minToolTier = val2.m_minToolTier;
			val3.m_hitEffect = val2.m_hitEffect;
			val3.m_destroyedEffect = val2.m_destroyedEffect;
			val3.m_switchEffect = val2.m_switchEffect;
		}
		else
		{
			ZLog.LogWarning((object)"[ChillFishing] Aquarium: 'piece_workbench' WearNTear not found -- using WearNTear defaults (100 HP, Wood material) instead.");
		}
		Container obj5 = val.AddComponent<Container>();
		obj5.m_name = "Aquarium";
		obj5.m_width = 1;
		obj5.m_height = 1;
		obj5.m_privacy = (PrivacySetting)2;
		GameObject prefab2 = scene.GetPrefab("piece_chest_wood");
		obj5.m_bkg = ((prefab2 == null) ? null : prefab2.GetComponent<Container>()?.m_bkg);
		val.AddComponent<AquaWatch>();
		scene.m_prefabs.Add(val);
		((Dictionary<int, GameObject>)AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs").GetValue(scene))[StringExtensionMethods.GetStableHashCode(((Object)val).name)] = val;
		Root = val;
		ZLog.Log((object)"[ChillFishing] Aquarium geometry built and registered as a findable prefab.");
	}

	public static void AddRecipe(ObjectDB objectDB)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Expected O, but got Unknown
		Piece component = Root.GetComponent<Piece>();
		GameObject itemPrefab = objectDB.GetItemPrefab("Crystal");
		if ((Object)(object)itemPrefab != (Object)null)
		{
			ItemDrop component2 = itemPrefab.GetComponent<ItemDrop>();
			component.m_resources = (Requirement[])(object)new Requirement[1]
			{
				new Requirement
				{
					m_resItem = component2,
					m_amount = 1,
					m_recover = true
				}
			};
			Sprite[] array = component2?.m_itemData?.m_shared?.m_icons;
			if (array != null && array.Length != 0)
			{
				component.m_icon = array[0];
			}
		}
		else
		{
			ZLog.LogWarning((object)"[ChillFishing] Aquarium: 'Crystal' item prefab still not found in ObjectDB.Awake -- piece registered with no cost/icon set.");
		}
		GameObject itemPrefab2 = objectDB.GetItemPrefab("Hammer");
		PieceTable val = ((!((Object)(object)itemPrefab2 != (Object)null)) ? null : itemPrefab2.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces);
		if ((Object)(object)val != (Object)null)
		{
			if (!val.m_pieces.Contains(Root))
			{
				val.m_pieces.Add(Root);
			}
			ZLog.Log((object)"[ChillFishing] Aquarium piece added to the hammer build menu (1 Crystal, Misc category).");
		}
		else
		{
			ZLog.LogWarning((object)"[ChillFishing] Aquarium: could not resolve the hammer's PieceTable via ItemDrop.m_itemData.m_shared.m_buildPieces -- piece exists but won't show in the build menu.");
		}
	}
}