Decompiled source of FishVsHunters v0.8.8

FishVsHunters.dll

Decompiled 20 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
using BepInEx;
using BepInEx.Configuration;
using FishNet;
using FishNet.Broadcast;
using FishNet.Connection;
using FishNet.Managing.Client;
using FishNet.Managing.Object;
using FishNet.Managing.Server;
using FishNet.Object;
using FishNet.Object.Synchronizing;
using FishNet.Serializing;
using FishNet.Transporting;
using FishVsHunters.debug;
using FishVsHunters.fish;
using FishVsHunters.match;
using FishVsHunters.net;
using FishVsHunters.ui;
using HarmonyLib;
using Steamworks;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("IslandRetentionChecks")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
namespace FishVsHunters
{
	[BepInPlugin("com.fishvshunters.mod", "Fish vs Hunters", "0.8.8")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.fishvshunters.mod";

		public const string Name = "Fish vs Hunters";

		public const string Version = "0.8.8";

		private Harmony _harmony;

		private void OnGUI()
		{
			MatchHud.Draw();
		}

		private void OnApplicationQuit()
		{
			RoundDirector.Flush();
		}

		private void Awake()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_005d: 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)
			Config.Init(((BaseUnityPlugin)this).Config);
			MutationCatalog.ApplyConfig();
			SkinCatalog.Validate();
			CustomSerializers.RegisterAll();
			_harmony = new Harmony("com.fishvshunters.mod");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} v{1} loaded. Role key: {2}; host round-mode key: {3}.", "Fish vs Hunters", "0.8.8", Config.BecomeFishKey.Value, Config.ToggleRestartKey.Value));
		}

		private void Update()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			NetHub.EnsureRegistered();
			MatchController.ClientPresentationTick();
			IslandRetention.Tick((MonoBehaviour)(object)this);
			if ((Object)(object)Server.Instance != (Object)null && ((NetworkBehaviour)Server.Instance).IsServerInitialized)
			{
				FishRegistry.HostTick();
				PreySpawner.HostTick();
				MatchController.HostMatchTick();
			}
			Keyboard current = Keyboard.current;
			if (current != null)
			{
				if (WasPressed(current, Config.ToggleRestartKey.Value))
				{
					RoundDirector.ToggleMode();
				}
				if (WasPressed(current, Config.BecomeFishKey.Value))
				{
					MatchController.RequestToggleFish();
				}
				else if (Config.DebugToolsEnabled.Value)
				{
					HandleDebugKeys(current);
				}
			}
		}

		private static void HandleDebugKeys(Keyboard kb)
		{
			//IL_0006: 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_004f: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: 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_0196: 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_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			if (WasPressed(kb, Config.DebugGiveXp100Key.Value))
			{
				MatchController.DebugForceEvolve();
				Debug.Log((object)"[FishVsHunters] DEBUG F7 -> next level/growth");
			}
			else if (WasPressed(kb, Config.DebugGiveXp500Key.Value))
			{
				MatchController.DebugGiveXp(500);
				Debug.Log((object)"[FishVsHunters] DEBUG +500 biomass");
			}
			else if (WasPressed(kb, Config.DebugForceEvolveKey.Value))
			{
				MatchController.DebugForceEvolve();
				Debug.Log((object)"[FishVsHunters] DEBUG force evolve");
			}
			else if (WasPressed(kb, Config.DebugSetLevelKey.Value))
			{
				MatchController.DebugSetLevel(Config.DebugSetLevelTarget.Value);
				Debug.Log((object)$"[FishVsHunters] DEBUG set level -> {Config.DebugSetLevelTarget.Value}");
			}
			else if (WasPressed(kb, Config.DebugHealKey.Value))
			{
				MatchController.DebugHeal();
				Debug.Log((object)"[FishVsHunters] DEBUG heal");
			}
			else if (WasPressed(kb, Config.DebugDamageKey.Value))
			{
				MatchController.DebugDamage(Config.DebugDamageAmount.Value);
				Debug.Log((object)$"[FishVsHunters] DEBUG damage -{Config.DebugDamageAmount.Value}");
			}
			else if (WasPressed(kb, Config.DebugClearMutationsKey.Value))
			{
				MatchController.DebugClearMutations();
				Debug.Log((object)"[FishVsHunters] DEBUG mutations cleared");
			}
			else if (WasPressed(kb, Config.DebugPrintStatsKey.Value))
			{
				Debug.Log((object)("[FishVsHunters] DEBUG stats: " + MatchController.DebugStatsSummary()));
			}
			else if (WasPressed(kb, Config.DebugPrintXpTableKey.Value))
			{
				DebugTools.PrintXpTable();
			}
			else if (WasPressed(kb, Config.DebugForcePathChoiceKey.Value))
			{
				MatchController.DebugForcePathChoice();
				Debug.Log((object)"[FishVsHunters] DEBUG force path choice");
			}
			else if (WasPressed(kb, Config.DebugChoosePrimalKey.Value))
			{
				MatchController.DebugChoosePath(EvolutionPath.Primal);
				Debug.Log((object)"[FishVsHunters] DEBUG choose PRIMAL");
			}
			else if (WasPressed(kb, Config.DebugChooseIntelligenceKey.Value))
			{
				MatchController.DebugChoosePath(EvolutionPath.Intelligence);
				Debug.Log((object)"[FishVsHunters] DEBUG choose INTELLIGENCE");
			}
			else if (WasPressed(kb, Config.DebugSpawnPreyKey.Value))
			{
				PreySpawner.DebugSpawnOne(MatchController.GetHostLocalFishRuntime());
				Debug.Log((object)"[FishVsHunters] DEBUG spawn prey");
			}
			else if (WasPressed(kb, Config.DebugNearestHunterHpKey.Value))
			{
				DebugTools.LogNearestHunterHp(((Object)(object)MatchController.LocalFishBody != (Object)null) ? ((Component)MatchController.LocalFishBody).transform.position : (((Object)(object)Player.LocalPlayer != (Object)null) ? Player.LocalPlayer.Transform.position : Vector3.zero), Config.DebugNearestRange.Value);
			}
			else if (WasPressed(kb, Config.DebugTestBiteHunterKey.Value))
			{
				MatchController.LocalFishController?.DebugForceBite();
			}
			else if (WasPressed(kb, Config.DebugTankBuildKey.Value))
			{
				ApplyBuildPreset(new MutationId[4]
				{
					MutationId.ThickSkin,
					MutationId.Armor,
					MutationId.Growth,
					MutationId.Ram
				}, 6, 3);
				Debug.Log((object)"[FishVsHunters] DEBUG Tank build applied (ThickSkin+Armor+Growth+Ram x3, level 6)");
			}
			else if (WasPressed(kb, Config.DebugSpeedBuildKey.Value))
			{
				ApplyBuildPreset(new MutationId[5]
				{
					MutationId.FastFins,
					MutationId.Dash,
					MutationId.SharpTeeth,
					MutationId.Bleed,
					MutationId.Sonar
				}, 6, 3);
				Debug.Log((object)"[FishVsHunters] DEBUG Speed/Damage build applied (FastFins+Dash+SharpTeeth+Bleed+Sonar x3, level 6)");
			}
		}

		private static void ApplyBuildPreset(MutationId[] ids, int level, int stacksEach)
		{
			MatchController.DebugSetLevel(level);
			for (int i = 0; i < stacksEach; i++)
			{
				MatchController.DebugApplyPreset(ids);
			}
		}

		private static bool WasPressed(Keyboard kb, Key key)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			KeyControl val = kb[key];
			if (val != null)
			{
				return ((ButtonControl)val).wasPressedThisFrame;
			}
			return false;
		}
	}
}
namespace FishVsHunters.ui
{
	internal class FishHud : MonoBehaviour
	{
		private Creature _body;

		private FishController _controller;

		private float _evolutionBannerUntil;

		private int _evolutionBannerLevel;

		private GUIStyle _panelStyle;

		private GUIStyle _titleStyle;

		private GUIStyle _lineStyle;

		private GUIStyle _boldLineStyle;

		private GUIStyle _bannerStyle;

		private GUIStyle _crossStyle;

		private GUIStyle _crossLabelStyle;

		private GUIStyle _cardStyle;

		private GUIStyle _cardNumberStyle;

		public void Initialize(Creature body, FishController controller)
		{
			_body = body;
			_controller = controller;
			_controller.OnLevelUp += OnLevelUp;
		}

		private void OnDestroy()
		{
			if ((Object)(object)_controller != (Object)null)
			{
				_controller.OnLevelUp -= OnLevelUp;
			}
		}

		private void OnLevelUp(int level)
		{
			_evolutionBannerLevel = level;
			_evolutionBannerUntil = Time.time + 2.5f;
		}

		private void EnsureStyles()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0028: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			//IL_0050: 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_005d: 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_0070: Expected O, but got Unknown
			//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_0093: 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_00a6: Expected O, but got Unknown
			//IL_00b1: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Expected O, but got Unknown
			//IL_0139: 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_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: 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_0164: Expected O, but got Unknown
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: 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_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Expected O, but got Unknown
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Expected O, but got Unknown
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Expected O, but got Unknown
			//IL_01d8: Expected O, but got Unknown
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Expected O, but got Unknown
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			if (_panelStyle == null)
			{
				Texture2D val = new Texture2D(1, 1);
				val.SetPixel(0, 0, new Color(0f, 0f, 0f, 0.6f));
				val.Apply();
				GUIStyle val2 = new GUIStyle();
				val2.normal.background = val;
				_panelStyle = val2;
				_titleStyle = new GUIStyle
				{
					fontSize = 18,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3
				};
				_titleStyle.normal.textColor = Color.white;
				_lineStyle = new GUIStyle
				{
					fontSize = 15,
					alignment = (TextAnchor)3,
					wordWrap = false
				};
				_lineStyle.normal.textColor = Color.white;
				_boldLineStyle = new GUIStyle(_lineStyle)
				{
					fontStyle = (FontStyle)1
				};
				_boldLineStyle.normal.textColor = new Color(1f, 0.85f, 0.3f);
				_bannerStyle = new GUIStyle
				{
					fontSize = 30,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4,
					wordWrap = true
				};
				_bannerStyle.normal.textColor = new Color(1f, 0.85f, 0.2f);
				_crossStyle = new GUIStyle
				{
					fontSize = 26,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				_crossLabelStyle = new GUIStyle
				{
					fontSize = 14,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				Texture2D val3 = new Texture2D(1, 1);
				val3.SetPixel(0, 0, new Color(0.035f, 0.12f, 0.16f, 0.96f));
				val3.Apply();
				_cardStyle = new GUIStyle(_panelStyle)
				{
					padding = new RectOffset(16, 16, 14, 14)
				};
				_cardStyle.normal.background = val3;
				_cardNumberStyle = new GUIStyle(_titleStyle)
				{
					fontSize = 30,
					alignment = (TextAnchor)1
				};
				_cardNumberStyle.normal.textColor = new Color(1f, 0.78f, 0.18f);
			}
		}

		private void OnGUI()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_body == (Object)null) && !((Object)(object)_controller == (Object)null))
			{
				EnsureStyles();
				GUI.color = Color.white;
				DrawStatsPanel();
				if (!DrawPathChoice())
				{
					DrawPerkChoice();
					DrawSkinChoice();
				}
				DrawSonarReadout();
				DrawBloodScent();
				DrawEvolutionBanner();
				DrawCrosshair();
			}
		}

		private void DrawStatsPanel()
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			CalculatedFishStats stats = _controller.Stats;
			bool flag = stats.DashUnlocked || stats.SonarUnlocked;
			int num = 11 + (flag ? (1 + (stats.DashUnlocked ? 1 : 0) + (stats.SonarUnlocked ? 1 : 0)) : 0);
			float num2 = 24f * (float)num + 16f;
			GUI.Box(new Rect(20f, 20f, 290f, num2), GUIContent.none, _panelStyle);
			float ly = 28f;
			Line("РЫБА", _titleStyle);
			Line($"Уровень: {_controller.Level} / {100}");
			Line("Путь: " + PathName(_controller.Path), _controller.AwaitingPathChoice ? _boldLineStyle : _lineStyle);
			Line("Форма: " + _controller.SkinDisplayName, _controller.AwaitingSkinChoice ? _boldLineStyle : _lineStyle);
			string text = ((_controller.Level >= 100) ? $"Биомасса: {_controller.Xp} (МАКС)" : (_controller.AwaitingSkinChoice ? $"Биомасса: {_controller.Xp}  (нужен выбор формы)" : $"Биомасса: {_controller.Xp} / {_controller.NextThreshold}"));
			Line(text);
			Line($"ХП: {_body._hp.Value} / {_body.MaxHp}");
			Line($"Броня: {stats.ArmorPercent:0}%");
			Line($"Урон укуса: {stats.BiteDamage:0}");
			float biteCooldownRemaining = _controller.BiteCooldownRemaining;
			Line((biteCooldownRemaining > 0f) ? $"Укус: {biteCooldownRemaining:0.0}с" : "Укус: ГОТОВ", (biteCooldownRemaining > 0f) ? _lineStyle : _boldLineStyle);
			Line($"Скорость: {stats.SwimSpeed:0.0}");
			Line($"Размер: {stats.Scale:0.00}x");
			if (flag)
			{
				Line("АКТИВНЫЕ:", _boldLineStyle);
				if (stats.DashUnlocked)
				{
					float dashCooldownRemaining = _controller.DashCooldownRemaining;
					Line((dashCooldownRemaining > 0f) ? $"[Q] Рывок — {dashCooldownRemaining:0.0}с" : "[Q] Рывок — ГОТОВ");
				}
				if (stats.SonarUnlocked)
				{
					float sonarCooldownRemaining = _controller.SonarCooldownRemaining;
					Line((sonarCooldownRemaining > 0f) ? $"[E] Сонар — {sonarCooldownRemaining:0.0}с" : "[E] Сонар — ГОТОВ");
				}
			}
			void Line(string text2, GUIStyle style = null)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				GUI.Label(new Rect(32f, ly, 266f, 24f), text2, style ?? _lineStyle);
				ly += 24f;
			}
		}

		private void DrawPerkChoice()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_0077: 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_0087: Expected O, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: 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_00cf: 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)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			//IL_00fd: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected O, but got Unknown
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			MutationId[] pendingChoice = _controller.PendingChoice;
			if (pendingChoice == null)
			{
				return;
			}
			float num = Mathf.Min(900f, (float)Screen.width - 40f);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor((float)Screen.width / 2f - num / 2f, (float)Screen.height * 0.56f, num, 250f);
			GUI.Box(val, GUIContent.none, _panelStyle);
			GUIStyle val2 = new GUIStyle(_titleStyle)
			{
				alignment = (TextAnchor)4,
				wordWrap = true,
				fontSize = 22
			};
			GUI.Label(new Rect(((Rect)(ref val)).x + 18f, ((Rect)(ref val)).y + 8f, num - 36f, 42f), "ЭВОЛЮЦИЯ! ВЫБЕРИ МУТАЦИЮ", val2);
			GUIStyle val3 = new GUIStyle(_lineStyle)
			{
				fontStyle = (FontStyle)1,
				wordWrap = true,
				alignment = (TextAnchor)1,
				fontSize = 17
			};
			val3.normal.textColor = new Color(0.65f, 0.93f, 1f);
			GUIStyle val4 = new GUIStyle(_lineStyle)
			{
				wordWrap = true,
				alignment = (TextAnchor)1,
				fontSize = 14
			};
			float num2 = (num - 36f - 28f) / 3f;
			float num3 = ((Rect)(ref val)).y + 42f + 10f;
			float num4 = ((Rect)(ref val)).height - 42f - 24f;
			Rect val5 = default(Rect);
			for (int i = 0; i < pendingChoice.Length; i++)
			{
				MutationDefinition mutationDefinition = MutationCatalog.Get(pendingChoice[i]);
				if (mutationDefinition != null)
				{
					int arg = _controller.StackOf(pendingChoice[i]) + 1;
					string text = ((mutationDefinition.Describe != null) ? mutationDefinition.Describe(arg) : "");
					((Rect)(ref val5))..ctor(((Rect)(ref val)).x + 18f + (float)i * (num2 + 14f), num3, num2, num4);
					GUI.Box(val5, GUIContent.none, _cardStyle);
					GUI.Label(new Rect(((Rect)(ref val5)).x + 8f, ((Rect)(ref val5)).y + 8f, ((Rect)(ref val5)).width - 16f, 38f), (i + 1).ToString(), _cardNumberStyle);
					GUI.Label(new Rect(((Rect)(ref val5)).x + 12f, ((Rect)(ref val5)).y + 50f, ((Rect)(ref val5)).width - 24f, 48f), mutationDefinition.DisplayName, val3);
					GUI.Label(new Rect(((Rect)(ref val5)).x + 12f, ((Rect)(ref val5)).y + 105f, ((Rect)(ref val5)).width - 24f, ((Rect)(ref val5)).height - 116f), text, val4);
				}
			}
		}

		private static string PathName(EvolutionPath p)
		{
			return p switch
			{
				EvolutionPath.Primal => "ИНСТИНКТ", 
				EvolutionPath.Intelligence => "РАЗУМ", 
				_ => "—", 
			};
		}

		private bool DrawPathChoice()
		{
			//IL_003b: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_0076: Expected O, but got Unknown
			//IL_007c: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_00a6: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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)
			//IL_00df: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			if (!_controller.AwaitingPathChoice)
			{
				return false;
			}
			float num = 664f;
			Rect panel = new Rect((float)Screen.width / 2f - 360f, (float)Screen.height * 0.16f, 720f, num);
			GUI.Box(panel, GUIContent.none, _panelStyle);
			GUIStyle style = new GUIStyle(_titleStyle)
			{
				alignment = (TextAnchor)4,
				fontSize = 22
			};
			GUIStyle val = new GUIStyle(_lineStyle)
			{
				fontStyle = (FontStyle)1,
				fontSize = 17
			};
			val.normal.textColor = new Color(1f, 0.85f, 0.3f);
			GUIStyle style2 = new GUIStyle(_lineStyle)
			{
				wordWrap = true
			};
			GUIStyle val2 = new GUIStyle(_lineStyle)
			{
				fontStyle = (FontStyle)1,
				alignment = (TextAnchor)4
			};
			val2.normal.textColor = new Color(1f, 0.5f, 0.4f);
			float ly = ((Rect)(ref panel)).y + 20f;
			L("ВЫБЕРИ ПУТЬ ЭВОЛЮЦИИ", style);
			ly += 13f;
			L("[1]  ИНСТИНКТ", val);
			L("Совершенствуй тело. Стань вершиной пищевой цепи.", style2, 20f);
			L("• огромный размер   • здоровье   • природная броня", style2, 20f);
			L("• укус   • таран   • регенерация   • чудовищные формы", style2, 20f);
			ly += 13f;
			L("[2]  РАЗУМ", val);
			L("Совершенствуй разум. Используй мир против своих врагов.", style2, 20f);
			L("• передвижение по суше   • взаимодействие с предметами", style2, 20f);
			L("• использование экипировки   • оружие   • техника", style2, 20f);
			ly += 13f;
			L("ВЫБОР НЕОБРАТИМ", val2);
			return true;
			void L(string text, GUIStyle val3, float indent = 0f)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				GUI.Label(new Rect(((Rect)(ref panel)).x + 20f + indent, ly, 680f - indent, 26f), text, val3);
				ly += 26f;
			}
		}

		private void DrawSkinChoice()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_0034: Expected O, but got Unknown
			//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)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Expected O, but got Unknown
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			if (!_controller.AwaitingSkinChoice)
			{
				return;
			}
			IReadOnlyList<int> pendingSkinIndices = _controller.PendingSkinIndices;
			GUIStyle val = new GUIStyle(_titleStyle)
			{
				alignment = (TextAnchor)4,
				wordWrap = true
			};
			if (pendingSkinIndices == null || pendingSkinIndices.Count == 0)
			{
				Rect val2 = new Rect((float)Screen.width / 2f - 320f, (float)Screen.height * 0.5f, 640f, 60f);
				GUI.Box(val2, GUIContent.none, _panelStyle);
				GUI.Label(val2, "ЭВОЛЮЦИЯ ДОСТУПНА — жди варианты...", val);
				return;
			}
			float num = 96f;
			float num2 = 64f + num * (float)pendingSkinIndices.Count;
			Rect val3 = default(Rect);
			((Rect)(ref val3))..ctor((float)Screen.width / 2f - 320f, (float)Screen.height * 0.4f, 640f, num2);
			GUI.Box(val3, GUIContent.none, _panelStyle);
			GUI.Label(new Rect(((Rect)(ref val3)).x + 16f, ((Rect)(ref val3)).y + 16f, 608f, 32f), "ЭВОЛЮЦИЯ! ВЫБЕРИ НОВУЮ ФОРМУ", val);
			GUIStyle val4 = new GUIStyle(_lineStyle)
			{
				fontStyle = (FontStyle)1,
				wordWrap = true
			};
			GUIStyle val5 = new GUIStyle(_lineStyle)
			{
				wordWrap = true
			};
			for (int i = 0; i < pendingSkinIndices.Count; i++)
			{
				float num3 = ((Rect)(ref val3)).y + 16f + 32f + num * (float)i;
				SkinDefinition byIndex = SkinCatalog.GetByIndex(pendingSkinIndices[i]);
				if (byIndex == null)
				{
					GUI.Label(new Rect(((Rect)(ref val3)).x + 16f, num3, 608f, 32f), $"[{i + 1}]  (неизвестная форма)", val4);
					continue;
				}
				SkinBaseStats skinBaseStats = byIndex.Evaluate(byIndex.MinLevel);
				SkinBaseStats skinBaseStats2 = byIndex.Evaluate(byIndex.MaxLevel);
				GUI.Label(new Rect(((Rect)(ref val3)).x + 16f, num3, 608f, 28.8f), $"[{i + 1}]  {byIndex.DisplayName}   (ур. {byIndex.MinLevel}–{byIndex.MaxLevel})", val4);
				GUI.Label(new Rect(((Rect)(ref val3)).x + 16f + 24f, num3 + 27.2f, 584f, 28.8f), $"ХП {skinBaseStats.MaxHp:0}→{skinBaseStats2.MaxHp:0}  ·  Урон {skinBaseStats.BiteDamage:0}→{skinBaseStats2.BiteDamage:0}  ·  Скор {skinBaseStats.SwimSpeed:0.0}  ·  Броня {skinBaseStats.ArmorPercent:0}%", val5);
				GUI.Label(new Rect(((Rect)(ref val3)).x + 16f + 24f, num3 + 54.4f, 584f, 28.8f), $"Размер {skinBaseStats.Scale:0.0}→{skinBaseStats2.Scale:0.0}x  ·  Поворот {skinBaseStats.TurnSpeedDegPerSec:0}°/с  ·  Масса {skinBaseStats.Mass:0}", val5);
			}
		}

		private void DrawSonarReadout()
		{
			IReadOnlyList<string> sonarLines = _controller.SonarLines;
			if (sonarLines != null && sonarLines.Count != 0)
			{
				DrawSidePanel("СОНАР", sonarLines, 210f);
			}
		}

		private void DrawBloodScent()
		{
			IReadOnlyList<string> bloodScentLines = _controller.BloodScentLines;
			if (bloodScentLines != null && bloodScentLines.Count != 0)
			{
				float yPos = ((_controller.SonarLines != null && _controller.SonarLines.Count > 0) ? 340f : 210f);
				DrawSidePanel("КРОВАВЫЙ НЮХ", bloodScentLines, yPos);
			}
		}

		private void DrawSidePanel(string title, IReadOnlyList<string> lines, float yPos)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			float num = 22f * (float)(lines.Count + 1) + 20f;
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(20f, yPos, 280f, num);
			GUI.Box(val, GUIContent.none, _panelStyle);
			GUI.Label(new Rect(((Rect)(ref val)).x + 10f, ((Rect)(ref val)).y + 10f, 260f, 22f), title, _boldLineStyle);
			for (int i = 0; i < lines.Count; i++)
			{
				GUI.Label(new Rect(((Rect)(ref val)).x + 10f, ((Rect)(ref val)).y + 10f + 22f * (float)(i + 1), 260f, 22f), lines[i], _lineStyle);
			}
		}

		private void DrawEvolutionBanner()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if (!(Time.time >= _evolutionBannerUntil))
			{
				GUI.Label(new Rect((float)Screen.width / 2f - 300f, (float)Screen.height * 0.18f, 600f, 80f), $"ЭВОЛЮЦИЯ!\nУРОВЕНЬ {_evolutionBannerLevel}", _bannerStyle);
			}
		}

		private void DrawCrosshair()
		{
			//IL_005c: 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_0061: 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_008b: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			string aimLabel = _controller.AimLabel;
			bool num = !string.IsNullOrEmpty(aimLabel);
			float num2 = (float)Screen.width / 2f;
			float num3 = (float)Screen.height / 2f;
			Color textColor = (num ? new Color(1f, 0.25f, 0.2f) : new Color(1f, 1f, 1f, 0.85f));
			_crossStyle.normal.textColor = textColor;
			GUI.Label(new Rect(num2 - 16f, num3 - 16f, 32f, 32f), "+", _crossStyle);
			if (num)
			{
				_crossLabelStyle.normal.textColor = textColor;
				GUI.Label(new Rect(num2 - 150f, num3 + 14f, 300f, 22f), aimLabel, _crossLabelStyle);
			}
		}
	}
	internal static class MatchHud
	{
		internal static void Draw()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: 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_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			if (InstanceFinder.IsClientStarted && !((Object)(object)Player.LocalPlayer == (Object)null) && NetHub.HasRoster)
			{
				float num = Mathf.Max(10, Screen.width - 420);
				string arg = (NetHub.ClientAutoRestart ? "Победы и новый раунд" : "Без побед · постоянный респавн");
				string arg2 = (InstanceFinder.IsServerStarted ? $"{Config.ToggleRestartKey.Value} — переключить режим" : "Режим меняет хост");
				GUI.Box(new Rect(num, 12f, 408f, 64f), $"Раунд {NetHub.ClientRound} · {arg}\n{arg2}");
				if (InstanceFinder.IsServerStarted && PauseManager.IsPaused && GUI.Button(new Rect(num, 80f, 408f, 32f), NetHub.ClientAutoRestart ? "Отключить победы: включить респавн" : "Включить победы и новый раунд"))
				{
					RoundDirector.ToggleMode();
				}
				byte clientWinner = NetHub.ClientWinner;
				if (clientWinner != 0)
				{
					string text = clientWinner switch
					{
						2 => "ОХОТНИКИ ПОБЕДИЛИ!", 
						1 => "РЫБЫ ПОБЕДИЛИ!", 
						_ => "НИЧЬЯ — ОБЕ КОМАНДЫ ПОГИБЛИ", 
					};
					GUIStyle val = new GUIStyle(GUI.skin.box)
					{
						fontSize = 28,
						fontStyle = (FontStyle)1,
						alignment = (TextAnchor)4
					};
					GUI.Box(new Rect((float)Screen.width * 0.5f - 340f, 100f, 680f, 78f), text, val);
				}
				if (NetHub.ClientCountdown >= 0f)
				{
					GUI.Box(new Rect((float)Screen.width * 0.5f - 200f, 182f, 400f, 36f), $"Новый раунд через {Mathf.CeilToInt(NetHub.ClientCountdown)} сек.");
				}
				else if (NetHub.LocalDead)
				{
					GUI.Box(new Rect((float)Screen.width * 0.5f - 220f, (float)(Screen.height - 110), 440f, 46f), NetHub.ClientAutoRestart ? "Вы погибли. Ожидайте окончания раунда." : "Вы погибли. Возрождение через несколько секунд.");
				}
			}
		}
	}
}
namespace FishVsHunters.patches
{
	[HarmonyPatch(typeof(Creature), "ServerChangeHp")]
	internal static class ArmorPatch
	{
		private static void Prefix(Creature __instance, ref int damage)
		{
			if (damage <= 0 || !((NetworkBehaviour)__instance).IsServerInitialized)
			{
				return;
			}
			FishRuntime byBody = FishRegistry.GetByBody(__instance);
			if (byBody != null)
			{
				byBody.LastDamageTime = Time.time;
				float armorPercent = byBody.Stats.ArmorPercent;
				if (armorPercent > 0f)
				{
					damage = Mathf.Max(1, Mathf.RoundToInt((float)damage * (1f - armorPercent / 100f)));
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class CaughtFishPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Item), "SetAttachedRod")]
		private static void RodPostfix(Item __instance)
		{
			PreySpawner.PreserveCatch(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Item), "SetSyncedHolder")]
		private static void HolderPostfix(Item __instance)
		{
			PreySpawner.PreserveCatch(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ItemManager), "SpawnSavedItem")]
		private static void LoadedPostfix(Item __result)
		{
			PreySpawner.RestoreCatch(__result);
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class FishInputBlockPatch
	{
		private static void Postfix(Player __instance, ref bool __result)
		{
			if (MatchController.IsHumanHidden(__instance) && !MatchController.IsIntelligenceFish(__instance))
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerVitals), "TakeDamage")]
	internal static class HiddenHumanDamagePatch
	{
		private static bool Prefix(PlayerVitals __instance)
		{
			Player val = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponentInParent<Player>() : null);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			FishRuntime byOwner = FishRegistry.GetByOwner(((NetworkBehaviour)val).Owner);
			if (byOwner != null)
			{
				return (Object)(object)byOwner.Body == (Object)null;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(PlayerUnderwater), "SetSoundsPlaying")]
	internal static class HiddenHumanUnderwaterPatch
	{
		private static void Prefix(PlayerUnderwater __instance, ref bool shouldPlay)
		{
			if (shouldPlay && MatchController.IsHumanHidden(((Component)__instance).GetComponentInParent<Player>()))
			{
				shouldPlay = false;
			}
		}
	}
	[HarmonyPatch]
	internal static class IslandRetentionPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(IslandManager), "QueueRequest")]
		private static bool QueuePrefix(byte islandId)
		{
			return IslandRetention.Queue(islandId);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(IslandManager), "ProcessRequest")]
		private static void RequestPrefix(byte islandId)
		{
			if (islandId == byte.MaxValue)
			{
				IslandRetention.Reset();
			}
			IslandRetention.Request(islandId);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(IslandManager), "ProcessRequest")]
		private static void RequestPostfix(ref IEnumerator __result)
		{
			__result = IslandRetention.TrackTravel(__result);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(IslandManager), "OnDestroy")]
		private static void DestroyPostfix()
		{
			IslandRetention.Reset();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(IslandManager), "UnloadAllIslandsRoutine")]
		private static bool UnloadPrefix(ref IEnumerator __result)
		{
			if (!IslandRetention.KeepDuringTravel)
			{
				return true;
			}
			__result = KeepIslands();
			return false;
		}

		private static IEnumerator KeepIslands()
		{
			if ((Object)(object)Server.Instance != (Object)null && ((NetworkBehaviour)Server.Instance).IsServerInitialized)
			{
				ItemManager.OnIslandUnloaded();
			}
			yield break;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Island), "Awake")]
		private static void IslandPostfix(Island __instance)
		{
			IslandRetention.Record(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Island), "Start")]
		private static void IslandStartPostfix(Island __instance)
		{
			IslandRetention.Record(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(SpawnManager), "Awake")]
		private static void SpawnPostfix(SpawnManager __instance)
		{
			IslandRetention.Record(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(IslandManager), "OnIslandChange")]
		private static void ChangedPostfix()
		{
			IslandRetention.SelectCurrent();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ItemManager), "RemoveItemsFarAwar")]
		private static void CleanupPrefix(List<Item> toRemove)
		{
			toRemove.RemoveAll(IslandRetention.ProtectFromCleanup);
		}
	}
	[HarmonyPatch]
	internal static class IslandLoadOncePatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.EnumeratorMoveNext((MethodBase)AccessTools.Method(typeof(IslandManager), "ProcessRequest", (Type[])null, (Type[])null));
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo original = AccessTools.Method(typeof(SceneManager), "LoadSceneAsync", new Type[2]
			{
				typeof(int),
				typeof(LoadSceneMode)
			}, (Type[])null);
			MethodInfo replacement = AccessTools.Method(typeof(IslandRetention), "LoadOnce", (Type[])null, (Type[])null);
			int replacements = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, original))
				{
					instruction.operand = replacement;
					replacements++;
				}
				yield return instruction;
			}
			if (replacements != 1)
			{
				throw new InvalidOperationException("Island loading patch: expected exactly one LoadSceneAsync call.");
			}
		}
	}
	[HarmonyPatch(typeof(DazedUtils), "AllPlayersNearbyCheck")]
	internal static class IslandTravelPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Vector3 point, float dist, ref bool __result)
		{
			//IL_006e: 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_0073: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			if (__result)
			{
				return;
			}
			bool flag = false;
			float num = dist * dist;
			foreach (Player player in PlayerManager.Players)
			{
				if ((Object)(object)player == (Object)null)
				{
					return;
				}
				if (MatchController.IsHumanHidden(player) || FishRegistry.GetByOwner(((NetworkBehaviour)player).Owner) != null)
				{
					flag = true;
					continue;
				}
				Vector3 val = (player.Dying.IsDead ? ((Component)player.Dying.DeadPlayer).transform.position : player.Transform.position) - point;
				if (((Vector3)(ref val)).sqrMagnitude < num)
				{
					continue;
				}
				return;
			}
			if (flag)
			{
				__result = true;
			}
		}
	}
	[HarmonyPatch]
	internal static class SessionPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Server), "OnStopClient")]
		private static void StopClient()
		{
			NetHub.ResetClient();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Server), "OnStopServer")]
		private static void BeforeStopServer()
		{
			RoundDirector.Flush();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Server), "OnStopServer")]
		private static void StopServer()
		{
			RoundDirector.StopServer();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(SaveManager), "SaveServer")]
		private static void Save()
		{
			RoundDirector.Flush();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Server), "RpcLogic___RespawnPlayer___2210451296")]
		private static bool RespawnPrefix()
		{
			return !RoundDirector.LockRespawn;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(PlayerDying), "LocalRespawn")]
		private static bool LocalRespawnPrefix()
		{
			return !NetHub.ClientRoundLocked;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(SaveManager), "CanSaveWorldItem")]
		private static void WorldItemPostfix(Item item, ref bool __result)
		{
			if (__result && (Object)(object)item != (Object)null && (Object)(object)item.Creature != (Object)null && (FishRegistry.GetByBody(item.Creature) != null || PreySpawner.IsWild(item.Creature)))
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(SteamManager), "LeaveLobby")]
	internal static class SteamShutdownPatch
	{
		private static void LeaveIfAvailable(CSteamID lobby)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				SteamMatchmaking.LeaveLobby(lobby);
			}
			catch (InvalidOperationException ex) when (ex.Message == "Steamworks is not initialized.")
			{
				Debug.Log((object)"[FishVsHunters] Steam already shut down; finishing local lobby cleanup.");
			}
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo original = AccessTools.Method(typeof(SteamMatchmaking), "LeaveLobby", (Type[])null, (Type[])null);
			MethodInfo replacement = AccessTools.Method(typeof(SteamShutdownPatch), "LeaveIfAvailable", (Type[])null, (Type[])null);
			int count = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, original))
				{
					instruction.operand = replacement;
					count++;
				}
				yield return instruction;
			}
			if (count != 1)
			{
				throw new InvalidOperationException("Steam shutdown patch expected one LeaveLobby call.");
			}
		}
	}
	[HarmonyPatch]
	internal static class VanillaCrabMovementPatch
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Crab), "UpdateMovement")]
		private static bool CrabPrefix(Crab __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				return (Object)(object)((Component)__instance).GetComponent<FishController>() == (Object)null;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Spidercrab), "UpdateMovement")]
		private static bool SpidercrabPrefix(Spidercrab __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				return (Object)(object)((Component)__instance).GetComponent<FishController>() == (Object)null;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(BowheadWhale), "UpdateMovement")]
		private static bool WhalePrefix(BowheadWhale __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				return (Object)(object)((Component)__instance).GetComponent<FishController>() == (Object)null;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(BowheadWhale), "FixedUpdate")]
		private static bool WhaleFixedPrefix(BowheadWhale __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				return (Object)(object)((Component)__instance).GetComponent<FishController>() == (Object)null;
			}
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(CrabLegs), "GetHorizontalVelocity")]
		private static void LegVelocityPostfix(CrabLegs __instance, ref Vector3 __result)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			FishController fishController = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponentInParent<FishController>() : null);
			if (!((Object)(object)fishController == (Object)null) && !((Object)(object)fishController.Body == (Object)null) && !((Object)(object)((Item)fishController.Body).Rig == (Object)null))
			{
				__result = ((Item)fishController.Body).Rig.linearVelocity;
				__result.y = 0f;
			}
		}
	}
	[HarmonyPatch(typeof(Fish), "UpdateMovement")]
	internal static class VanillaFishFlapPatch
	{
		private static bool Prefix(Fish __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				return (Object)(object)((Component)__instance).GetComponent<FishController>() == (Object)null;
			}
			return true;
		}
	}
}
namespace FishVsHunters.net
{
	public struct C2S_BecomeFishRequest : IBroadcast
	{
		public bool Leave;
	}
	public struct S2C_FishAssigned : IBroadcast
	{
		public int BodyObjectId;

		public bool Removed;
	}
	public struct S2C_FishPrivateState : IBroadcast
	{
		public FishStatsWire Stats;

		public int NextXp;

		public int BodyObjectId;

		public int Level;

		public int Xp;

		public byte SkinIndex;

		public bool AwaitingSkinChoice;

		public bool AwaitingMutationChoice;

		public byte Path;

		public bool AwaitingPathChoice;

		public byte ThickSkin;

		public byte Armor;

		public byte Devourer;

		public byte Regeneration;

		public byte SharpTeeth;

		public byte FastJaw;

		public byte Bleed;

		public byte Predator;

		public byte FastFins;

		public byte Maneuverability;

		public byte Dash;

		public byte ImprovedDash;

		public byte Growth;

		public byte Gigantism;

		public byte Ram;

		public byte Sonar;

		public byte ImprovedSonar;

		public byte BloodScent;

		public byte TidalWave;

		public byte Manipulation;
	}
	public struct S2C_MutationOffer : IBroadcast
	{
		public int BodyObjectId;

		public byte Count;

		public byte Option0;

		public byte Option1;

		public byte Option2;
	}
	public struct C2S_MutationChoice : IBroadcast
	{
		public byte OptionIndex;
	}
	public struct C2S_BiteReport : IBroadcast
	{
		public int XpAmount;

		public bool WasPreyEaten;
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public struct C2S_BiteVisual : IBroadcast
	{
	}
	public struct S2C_BiteVisual : IBroadcast
	{
		public int BodyObjectId;
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	public struct C2S_Wave : IBroadcast
	{
	}
	public struct S2C_IslandResidency : IBroadcast
	{
		public byte Current;

		public string Builds;
	}
	public struct S2C_Wave : IBroadcast
	{
		public int BodyObjectId;

		public byte Stack;
	}
	public struct S2C_SkinOffer : IBroadcast
	{
		public int BodyObjectId;

		public byte Count;

		public byte Option0;

		public byte Option1;

		public byte Option2;
	}
	public struct C2S_SkinChoice : IBroadcast
	{
		public byte OptionIndex;
	}
	public struct S2C_PathOffer : IBroadcast
	{
		public int BodyObjectId;
	}
	public struct C2S_PathChoice : IBroadcast
	{
		public byte Path;
	}
	public struct S2C_FishBodySwapped : IBroadcast
	{
		public int OldObjectId;

		public int NewObjectId;

		public byte SkinIndex;
	}
	public struct FishEvolutionBroadcast : IBroadcast
	{
		public int BodyObjectId;

		public byte Level;

		public float Scale;
	}
	internal static class CustomSerializers
	{
		public static void RegisterAll()
		{
			RosterWire.Register();
			GenericWriter<S2C_IslandResidency>.SetWrite((Action<Writer, S2C_IslandResidency>)delegate(Writer writer, S2C_IslandResidency v)
			{
				writer.WriteUInt8Unpacked(v.Current);
				writer.WriteString(v.Builds);
			});
			GenericReader<S2C_IslandResidency>.SetRead((Func<Reader, S2C_IslandResidency>)((Reader reader) => new S2C_IslandResidency
			{
				Current = reader.ReadUInt8Unpacked(),
				Builds = reader.ReadStringAllocated()
			}));
			GenericWriter<C2S_BecomeFishRequest>.SetWrite((Action<Writer, C2S_BecomeFishRequest>)WriteBecomeFishRequest);
			GenericReader<C2S_BecomeFishRequest>.SetRead((Func<Reader, C2S_BecomeFishRequest>)ReadBecomeFishRequest);
			GenericWriter<S2C_FishAssigned>.SetWrite((Action<Writer, S2C_FishAssigned>)WriteFishAssigned);
			GenericReader<S2C_FishAssigned>.SetRead((Func<Reader, S2C_FishAssigned>)ReadFishAssigned);
			GenericWriter<S2C_FishPrivateState>.SetWrite((Action<Writer, S2C_FishPrivateState>)WriteFishPrivateState);
			GenericReader<S2C_FishPrivateState>.SetRead((Func<Reader, S2C_FishPrivateState>)ReadFishPrivateState);
			GenericWriter<S2C_MutationOffer>.SetWrite((Action<Writer, S2C_MutationOffer>)WriteMutationOffer);
			GenericReader<S2C_MutationOffer>.SetRead((Func<Reader, S2C_MutationOffer>)ReadMutationOffer);
			GenericWriter<C2S_MutationChoice>.SetWrite((Action<Writer, C2S_MutationChoice>)WriteMutationChoice);
			GenericReader<C2S_MutationChoice>.SetRead((Func<Reader, C2S_MutationChoice>)ReadMutationChoice);
			GenericWriter<C2S_BiteReport>.SetWrite((Action<Writer, C2S_BiteReport>)WriteBiteReport);
			GenericReader<C2S_BiteReport>.SetRead((Func<Reader, C2S_BiteReport>)ReadBiteReport);
			GenericWriter<C2S_BiteVisual>.SetWrite((Action<Writer, C2S_BiteVisual>)delegate
			{
			});
			GenericReader<C2S_BiteVisual>.SetRead((Func<Reader, C2S_BiteVisual>)((Reader reader) => default(C2S_BiteVisual)));
			GenericWriter<S2C_BiteVisual>.SetWrite((Action<Writer, S2C_BiteVisual>)delegate(Writer writer, S2C_BiteVisual v)
			{
				writer.WriteInt32(v.BodyObjectId);
			});
			GenericReader<S2C_BiteVisual>.SetRead((Func<Reader, S2C_BiteVisual>)((Reader reader) => new S2C_BiteVisual
			{
				BodyObjectId = reader.ReadInt32()
			}));
			GenericWriter<C2S_Wave>.SetWrite((Action<Writer, C2S_Wave>)delegate
			{
			});
			GenericReader<C2S_Wave>.SetRead((Func<Reader, C2S_Wave>)((Reader reader) => default(C2S_Wave)));
			GenericWriter<S2C_Wave>.SetWrite((Action<Writer, S2C_Wave>)delegate(Writer writer, S2C_Wave v)
			{
				writer.WriteInt32(v.BodyObjectId);
				writer.WriteUInt8Unpacked(v.Stack);
			});
			GenericReader<S2C_Wave>.SetRead((Func<Reader, S2C_Wave>)((Reader reader) => new S2C_Wave
			{
				BodyObjectId = reader.ReadInt32(),
				Stack = reader.ReadUInt8Unpacked()
			}));
			GenericWriter<FishEvolutionBroadcast>.SetWrite((Action<Writer, FishEvolutionBroadcast>)WriteFishEvolution);
			GenericReader<FishEvolutionBroadcast>.SetRead((Func<Reader, FishEvolutionBroadcast>)ReadFishEvolution);
			GenericWriter<S2C_SkinOffer>.SetWrite((Action<Writer, S2C_SkinOffer>)WriteSkinOffer);
			GenericReader<S2C_SkinOffer>.SetRead((Func<Reader, S2C_SkinOffer>)ReadSkinOffer);
			GenericWriter<C2S_SkinChoice>.SetWrite((Action<Writer, C2S_SkinChoice>)WriteSkinChoice);
			GenericReader<C2S_SkinChoice>.SetRead((Func<Reader, C2S_SkinChoice>)ReadSkinChoice);
			GenericWriter<S2C_FishBodySwapped>.SetWrite((Action<Writer, S2C_FishBodySwapped>)WriteFishBodySwapped);
			GenericReader<S2C_FishBodySwapped>.SetRead((Func<Reader, S2C_FishBodySwapped>)ReadFishBodySwapped);
			GenericWriter<S2C_PathOffer>.SetWrite((Action<Writer, S2C_PathOffer>)delegate(Writer writer, S2C_PathOffer v)
			{
				writer.WriteInt32(v.BodyObjectId);
			});
			GenericReader<S2C_PathOffer>.SetRead((Func<Reader, S2C_PathOffer>)((Reader reader) => new S2C_PathOffer
			{
				BodyObjectId = reader.ReadInt32()
			}));
			GenericWriter<C2S_PathChoice>.SetWrite((Action<Writer, C2S_PathChoice>)delegate(Writer writer, C2S_PathChoice v)
			{
				writer.WriteUInt8Unpacked(v.Path);
			});
			GenericReader<C2S_PathChoice>.SetRead((Func<Reader, C2S_PathChoice>)((Reader reader) => new C2S_PathChoice
			{
				Path = reader.ReadUInt8Unpacked()
			}));
		}

		private static void WriteBecomeFishRequest(Writer writer, C2S_BecomeFishRequest v)
		{
			writer.WriteBoolean(v.Leave);
		}

		private static C2S_BecomeFishRequest ReadBecomeFishRequest(Reader reader)
		{
			return new C2S_BecomeFishRequest
			{
				Leave = reader.ReadBoolean()
			};
		}

		private static void WriteFishAssigned(Writer writer, S2C_FishAssigned v)
		{
			writer.WriteInt32(v.BodyObjectId);
			writer.WriteBoolean(v.Removed);
		}

		private static S2C_FishAssigned ReadFishAssigned(Reader reader)
		{
			return new S2C_FishAssigned
			{
				BodyObjectId = reader.ReadInt32(),
				Removed = reader.ReadBoolean()
			};
		}

		private static void WriteFishPrivateState(Writer writer, S2C_FishPrivateState v)
		{
			FishStatsWire.Write(writer, v.Stats);
			writer.WriteInt32(v.NextXp);
			writer.WriteInt32(v.BodyObjectId);
			writer.WriteInt32(v.Level);
			writer.WriteInt32(v.Xp);
			writer.WriteUInt8Unpacked(v.SkinIndex);
			writer.WriteBoolean(v.AwaitingSkinChoice);
			writer.WriteBoolean(v.AwaitingMutationChoice);
			writer.WriteUInt8Unpacked(v.Path);
			writer.WriteBoolean(v.AwaitingPathChoice);
			writer.WriteUInt8Unpacked(v.ThickSkin);
			writer.WriteUInt8Unpacked(v.Armor);
			writer.WriteUInt8Unpacked(v.Devourer);
			writer.WriteUInt8Unpacked(v.Regeneration);
			writer.WriteUInt8Unpacked(v.SharpTeeth);
			writer.WriteUInt8Unpacked(v.FastJaw);
			writer.WriteUInt8Unpacked(v.Bleed);
			writer.WriteUInt8Unpacked(v.Predator);
			writer.WriteUInt8Unpacked(v.FastFins);
			writer.WriteUInt8Unpacked(v.Maneuverability);
			writer.WriteUInt8Unpacked(v.Dash);
			writer.WriteUInt8Unpacked(v.ImprovedDash);
			writer.WriteUInt8Unpacked(v.Growth);
			writer.WriteUInt8Unpacked(v.Gigantism);
			writer.WriteUInt8Unpacked(v.Ram);
			writer.WriteUInt8Unpacked(v.Sonar);
			writer.WriteUInt8Unpacked(v.ImprovedSonar);
			writer.WriteUInt8Unpacked(v.BloodScent);
			writer.WriteUInt8Unpacked(v.TidalWave);
			writer.WriteUInt8Unpacked(v.Manipulation);
		}

		private static S2C_FishPrivateState ReadFishPrivateState(Reader reader)
		{
			return new S2C_FishPrivateState
			{
				Stats = FishStatsWire.Read(reader),
				NextXp = reader.ReadInt32(),
				BodyObjectId = reader.ReadInt32(),
				Level = reader.ReadInt32(),
				Xp = reader.ReadInt32(),
				SkinIndex = reader.ReadUInt8Unpacked(),
				AwaitingSkinChoice = reader.ReadBoolean(),
				AwaitingMutationChoice = reader.ReadBoolean(),
				Path = reader.ReadUInt8Unpacked(),
				AwaitingPathChoice = reader.ReadBoolean(),
				ThickSkin = reader.ReadUInt8Unpacked(),
				Armor = reader.ReadUInt8Unpacked(),
				Devourer = reader.ReadUInt8Unpacked(),
				Regeneration = reader.ReadUInt8Unpacked(),
				SharpTeeth = reader.ReadUInt8Unpacked(),
				FastJaw = reader.ReadUInt8Unpacked(),
				Bleed = reader.ReadUInt8Unpacked(),
				Predator = reader.ReadUInt8Unpacked(),
				FastFins = reader.ReadUInt8Unpacked(),
				Maneuverability = reader.ReadUInt8Unpacked(),
				Dash = reader.ReadUInt8Unpacked(),
				ImprovedDash = reader.ReadUInt8Unpacked(),
				Growth = reader.ReadUInt8Unpacked(),
				Gigantism = reader.ReadUInt8Unpacked(),
				Ram = reader.ReadUInt8Unpacked(),
				Sonar = reader.ReadUInt8Unpacked(),
				ImprovedSonar = reader.ReadUInt8Unpacked(),
				BloodScent = reader.ReadUInt8Unpacked(),
				TidalWave = reader.ReadUInt8Unpacked(),
				Manipulation = reader.ReadUInt8Unpacked()
			};
		}

		private static void WriteMutationOffer(Writer writer, S2C_MutationOffer v)
		{
			writer.WriteInt32(v.BodyObjectId);
			writer.WriteUInt8Unpacked(v.Count);
			writer.WriteUInt8Unpacked(v.Option0);
			writer.WriteUInt8Unpacked(v.Option1);
			writer.WriteUInt8Unpacked(v.Option2);
		}

		private static S2C_MutationOffer ReadMutationOffer(Reader reader)
		{
			return new S2C_MutationOffer
			{
				BodyObjectId = reader.ReadInt32(),
				Count = reader.ReadUInt8Unpacked(),
				Option0 = reader.ReadUInt8Unpacked(),
				Option1 = reader.ReadUInt8Unpacked(),
				Option2 = reader.ReadUInt8Unpacked()
			};
		}

		private static void WriteMutationChoice(Writer writer, C2S_MutationChoice v)
		{
			writer.WriteUInt8Unpacked(v.OptionIndex);
		}

		private static C2S_MutationChoice ReadMutationChoice(Reader reader)
		{
			return new C2S_MutationChoice
			{
				OptionIndex = reader.ReadUInt8Unpacked()
			};
		}

		private static void WriteBiteReport(Writer writer, C2S_BiteReport v)
		{
			writer.WriteInt32(v.XpAmount);
			writer.WriteBoolean(v.WasPreyEaten);
		}

		private static C2S_BiteReport ReadBiteReport(Reader reader)
		{
			return new C2S_BiteReport
			{
				XpAmount = reader.ReadInt32(),
				WasPreyEaten = reader.ReadBoolean()
			};
		}

		private static void WriteFishEvolution(Writer writer, FishEvolutionBroadcast v)
		{
			writer.WriteInt32(v.BodyObjectId);
			writer.WriteUInt8Unpacked(v.Level);
			writer.WriteSingle(v.Scale);
		}

		private static FishEvolutionBroadcast ReadFishEvolution(Reader reader)
		{
			return new FishEvolutionBroadcast
			{
				BodyObjectId = reader.ReadInt32(),
				Level = reader.ReadUInt8Unpacked(),
				Scale = reader.ReadSingle()
			};
		}

		private static void WriteSkinOffer(Writer writer, S2C_SkinOffer v)
		{
			writer.WriteInt32(v.BodyObjectId);
			writer.WriteUInt8Unpacked(v.Count);
			writer.WriteUInt8Unpacked(v.Option0);
			writer.WriteUInt8Unpacked(v.Option1);
			writer.WriteUInt8Unpacked(v.Option2);
		}

		private static S2C_SkinOffer ReadSkinOffer(Reader reader)
		{
			return new S2C_SkinOffer
			{
				BodyObjectId = reader.ReadInt32(),
				Count = reader.ReadUInt8Unpacked(),
				Option0 = reader.ReadUInt8Unpacked(),
				Option1 = reader.ReadUInt8Unpacked(),
				Option2 = reader.ReadUInt8Unpacked()
			};
		}

		private static void WriteSkinChoice(Writer writer, C2S_SkinChoice v)
		{
			writer.WriteUInt8Unpacked(v.OptionIndex);
		}

		private static C2S_SkinChoice ReadSkinChoice(Reader reader)
		{
			return new C2S_SkinChoice
			{
				OptionIndex = reader.ReadUInt8Unpacked()
			};
		}

		private static void WriteFishBodySwapped(Writer writer, S2C_FishBodySwapped v)
		{
			writer.WriteInt32(v.OldObjectId);
			writer.WriteInt32(v.NewObjectId);
			writer.WriteUInt8Unpacked(v.SkinIndex);
		}

		private static S2C_FishBodySwapped ReadFishBodySwapped(Reader reader)
		{
			return new S2C_FishBodySwapped
			{
				OldObjectId = reader.ReadInt32(),
				NewObjectId = reader.ReadInt32(),
				SkinIndex = reader.ReadUInt8Unpacked()
			};
		}
	}
	public struct FishStatsWire
	{
		public int Level;

		public float MaxHp;

		public float ArmorPercent;

		public float BiteDamage;

		public float BiteCooldown;

		public float BiteRange;

		public float BiteRadius;

		public float SwimSpeed;

		public float TurnSpeedDegPerSec;

		public float Acceleration;

		public float Scale;

		public float Mass;

		public float MassMultiplier;

		public bool DashUnlocked;

		public float DashCooldown;

		public float DashForce;

		public bool SonarUnlocked;

		public float SonarCooldown;

		public float SonarDuration;

		public bool RamUnlocked;

		public bool BleedUnlocked;

		public float BleedDamagePerTick;

		public bool PredatorUnlocked;

		public float PredatorBonusDamagePercent;

		public bool DevourerUnlocked;

		public float DevourerHealPercent;

		public bool RegenerationUnlocked;

		public float RegenerationHpPerTick;

		public bool BloodScentUnlocked;

		internal static FishStatsWire From(CalculatedFishStats value)
		{
			return new FishStatsWire
			{
				Level = value.Level,
				MaxHp = value.MaxHp,
				ArmorPercent = value.ArmorPercent,
				BiteDamage = value.BiteDamage,
				BiteCooldown = value.BiteCooldown,
				BiteRange = value.BiteRange,
				BiteRadius = value.BiteRadius,
				SwimSpeed = value.SwimSpeed,
				TurnSpeedDegPerSec = value.TurnSpeedDegPerSec,
				Acceleration = value.Acceleration,
				Scale = value.Scale,
				Mass = value.Mass,
				MassMultiplier = value.MassMultiplier,
				DashUnlocked = value.DashUnlocked,
				DashCooldown = value.DashCooldown,
				DashForce = value.DashForce,
				SonarUnlocked = value.SonarUnlocked,
				SonarCooldown = value.SonarCooldown,
				SonarDuration = value.SonarDuration,
				RamUnlocked = value.RamUnlocked,
				BleedUnlocked = value.BleedUnlocked,
				BleedDamagePerTick = value.BleedDamagePerTick,
				PredatorUnlocked = value.PredatorUnlocked,
				PredatorBonusDamagePercent = value.PredatorBonusDamagePercent,
				DevourerUnlocked = value.DevourerUnlocked,
				DevourerHealPercent = value.DevourerHealPercent,
				RegenerationUnlocked = value.RegenerationUnlocked,
				RegenerationHpPerTick = value.RegenerationHpPerTick,
				BloodScentUnlocked = value.BloodScentUnlocked
			};
		}

		internal CalculatedFishStats ToStats()
		{
			return new CalculatedFishStats
			{
				Level = Level,
				MaxHp = MaxHp,
				ArmorPercent = ArmorPercent,
				BiteDamage = BiteDamage,
				BiteCooldown = BiteCooldown,
				BiteRange = BiteRange,
				BiteRadius = BiteRadius,
				SwimSpeed = SwimSpeed,
				TurnSpeedDegPerSec = TurnSpeedDegPerSec,
				Acceleration = Acceleration,
				Scale = Scale,
				Mass = Mass,
				MassMultiplier = MassMultiplier,
				DashUnlocked = DashUnlocked,
				DashCooldown = DashCooldown,
				DashForce = DashForce,
				SonarUnlocked = SonarUnlocked,
				SonarCooldown = SonarCooldown,
				SonarDuration = SonarDuration,
				RamUnlocked = RamUnlocked,
				BleedUnlocked = BleedUnlocked,
				BleedDamagePerTick = BleedDamagePerTick,
				PredatorUnlocked = PredatorUnlocked,
				PredatorBonusDamagePercent = PredatorBonusDamagePercent,
				DevourerUnlocked = DevourerUnlocked,
				DevourerHealPercent = DevourerHealPercent,
				RegenerationUnlocked = RegenerationUnlocked,
				RegenerationHpPerTick = RegenerationHpPerTick,
				BloodScentUnlocked = BloodScentUnlocked
			};
		}

		internal static void Write(Writer writer, FishStatsWire value)
		{
			writer.WriteInt32(value.Level);
			writer.WriteSingle(value.MaxHp);
			writer.WriteSingle(value.ArmorPercent);
			writer.WriteSingle(value.BiteDamage);
			writer.WriteSingle(value.BiteCooldown);
			writer.WriteSingle(value.BiteRange);
			writer.WriteSingle(value.BiteRadius);
			writer.WriteSingle(value.SwimSpeed);
			writer.WriteSingle(value.TurnSpeedDegPerSec);
			writer.WriteSingle(value.Acceleration);
			writer.WriteSingle(value.Scale);
			writer.WriteSingle(value.Mass);
			writer.WriteSingle(value.MassMultiplier);
			writer.WriteBoolean(value.DashUnlocked);
			writer.WriteSingle(value.DashCooldown);
			writer.WriteSingle(value.DashForce);
			writer.WriteBoolean(value.SonarUnlocked);
			writer.WriteSingle(value.SonarCooldown);
			writer.WriteSingle(value.SonarDuration);
			writer.WriteBoolean(value.RamUnlocked);
			writer.WriteBoolean(value.BleedUnlocked);
			writer.WriteSingle(value.BleedDamagePerTick);
			writer.WriteBoolean(value.PredatorUnlocked);
			writer.WriteSingle(value.PredatorBonusDamagePercent);
			writer.WriteBoolean(value.DevourerUnlocked);
			writer.WriteSingle(value.DevourerHealPercent);
			writer.WriteBoolean(value.RegenerationUnlocked);
			writer.WriteSingle(value.RegenerationHpPerTick);
			writer.WriteBoolean(value.BloodScentUnlocked);
		}

		internal static FishStatsWire Read(Reader reader)
		{
			return new FishStatsWire
			{
				Level = reader.ReadInt32(),
				MaxHp = reader.ReadSingle(),
				ArmorPercent = reader.ReadSingle(),
				BiteDamage = reader.ReadSingle(),
				BiteCooldown = reader.ReadSingle(),
				BiteRange = reader.ReadSingle(),
				BiteRadius = reader.ReadSingle(),
				SwimSpeed = reader.ReadSingle(),
				TurnSpeedDegPerSec = reader.ReadSingle(),
				Acceleration = reader.ReadSingle(),
				Scale = reader.ReadSingle(),
				Mass = reader.ReadSingle(),
				MassMultiplier = reader.ReadSingle(),
				DashUnlocked = reader.ReadBoolean(),
				DashCooldown = reader.ReadSingle(),
				DashForce = reader.ReadSingle(),
				SonarUnlocked = reader.ReadBoolean(),
				SonarCooldown = reader.ReadSingle(),
				SonarDuration = reader.ReadSingle(),
				RamUnlocked = reader.ReadBoolean(),
				BleedUnlocked = reader.ReadBoolean(),
				BleedDamagePerTick = reader.ReadSingle(),
				PredatorUnlocked = reader.ReadBoolean(),
				PredatorBonusDamagePercent = reader.ReadSingle(),
				DevourerUnlocked = reader.ReadBoolean(),
				DevourerHealPercent = reader.ReadSingle(),
				RegenerationUnlocked = reader.ReadBoolean(),
				RegenerationHpPerTick = reader.ReadSingle(),
				BloodScentUnlocked = reader.ReadBoolean()
			};
		}
	}
	internal static class NetHub
	{
		private static bool _registered;

		private static ClientManager _clientManager;

		private static ServerManager _serverManager;

		private static readonly List<Action> Unregister = new List<Action>();

		private static S2C_Roster? _roster;

		private static int _revision;

		private static float _countdownUntil = -1f;

		private static float _winnerUntil;

		private static readonly Dictionary<int, S2C_FishPrivateState> _pendingPrivateStates = new Dictionary<int, S2C_FishPrivateState>();

		private static readonly Dictionary<int, S2C_MutationOffer> _pendingMutationOffers = new Dictionary<int, S2C_MutationOffer>();

		private static readonly Dictionary<int, S2C_SkinOffer> _pendingSkinOffers = new Dictionary<int, S2C_SkinOffer>();

		private static readonly Dictionary<int, S2C_PathOffer> _pendingPathOffers = new Dictionary<int, S2C_PathOffer>();

		private static readonly Dictionary<int, FishEvolutionBroadcast> _pendingEvolutions = new Dictionary<int, FishEvolutionBroadcast>();

		private static readonly Dictionary<int, S2C_BiteVisual> _pendingBiteVisuals = new Dictionary<int, S2C_BiteVisual>();

		public static byte ClientWinner
		{
			get
			{
				if (!_roster.HasValue || !_roster.Value.AutoRestart || !(Time.time < _winnerUntil))
				{
					return 0;
				}
				return _roster.Value.Winner;
			}
		}

		public static bool ClientRoundLocked
		{
			get
			{
				if (_roster.HasValue)
				{
					return _roster.Value.RoundLocked;
				}
				return false;
			}
		}

		public static bool ClientAutoRestart => _roster?.AutoRestart ?? true;

		public static int ClientRound => _roster?.Round ?? 1;

		public static float ClientCountdown
		{
			get
			{
				if (!(_countdownUntil < 0f))
				{
					return Mathf.Max(0f, _countdownUntil - Time.time);
				}
				return -1f;
			}
		}

		public static bool HasRoster => _roster.HasValue;

		public static bool LocalDead
		{
			get
			{
				if (!_roster.HasValue || (Object)(object)Player.LocalPlayer == (Object)null || ((NetworkBehaviour)Player.LocalPlayer).Owner == (NetworkConnection)null)
				{
					return false;
				}
				FishRosterEntry[] fish = _roster.Value.Fish;
				for (int i = 0; i < fish.Length; i++)
				{
					FishRosterEntry fishRosterEntry = fish[i];
					if (fishRosterEntry.OwnerId == ((NetworkBehaviour)Player.LocalPlayer).Owner.ClientId)
					{
						return fishRosterEntry.Dead;
					}
				}
				return Player.LocalPlayer.Vitals.Health <= 0;
			}
		}

		private static void RegisterClient<T>(Action<T, Channel> handler) where T : struct, IBroadcast
		{
			ClientManager manager = _clientManager;
			manager.RegisterBroadcast<T>(handler);
			Unregister.Add(delegate
			{
				if ((Object)(object)manager != (Object)null)
				{
					manager.UnregisterBroadcast<T>(handler);
				}
			});
		}

		private static void RegisterServer<T>(Action<NetworkConnection, T, Channel> handler) where T : struct, IBroadcast
		{
			ServerManager manager = _serverManager;
			manager.RegisterBroadcast<T>(handler, true);
			Unregister.Add(delegate
			{
				if ((Object)(object)manager != (Object)null)
				{
					manager.UnregisterBroadcast<T>(handler);
				}
			});
		}

		internal static void ResetClient()
		{
			MatchController.ResetClient();
			_roster = null;
			_countdownUntil = -1f;
			ClearPending();
			IslandRetention.StopSession();
			OceanSwell.Reset();
		}

		private static void ClearPending()
		{
			_pendingPrivateStates.Clear();
			_pendingMutationOffers.Clear();
			_pendingSkinOffers.Clear();
			_pendingPathOffers.Clear();
			_pendingEvolutions.Clear();
			_pendingBiteVisuals.Clear();
		}

		private static S2C_Roster BuildRoster()
		{
			List<FishRosterEntry> list = new List<FishRosterEntry>();
			foreach (FishRuntime item in FishRegistry.All)
			{
				if (!(item.OwnerConn == (NetworkConnection)null) && item.OwnerConn.IsActive)
				{
					CalculatedFishStats stats = item.Stats;
					list.Add(new FishRosterEntry
					{
						OwnerId = item.OwnerConn.ClientId,
						BodyId = (((Object)(object)item.Body != (Object)null) ? ((NetworkBehaviour)item.Body).ObjectId : (-1)),
						Dead = !item.Alive,
						Scale = stats.Scale,
						MaxHp = Mathf.RoundToInt(stats.MaxHp),
						Mass = stats.Mass
					});
				}
			}
			return new S2C_Roster
			{
				Session = RoundDirector.Session,
				Revision = ++_revision,
				Round = RoundDirector.Round,
				AutoRestart = RoundDirector.AutoRestart,
				RoundLocked = RoundDirector.LockRespawn,
				Countdown = RoundDirector.Countdown,
				Winner = RoundDirector.Winner,
				WinnerSeconds = RoundDirector.WinnerSeconds,
				Fish = list.ToArray()
			};
		}

		internal static void BroadcastRoster()
		{
			if (InstanceFinder.IsServerStarted && RoundDirector.Running)
			{
				InstanceFinder.ServerManager.Broadcast<S2C_Roster>(BuildRoster(), true, (Channel)0);
			}
		}

		private static void OnAuthenticationResult(NetworkConnection conn, bool authenticated)
		{
			if (authenticated && !(conn == (NetworkConnection)null) && RoundDirector.Running)
			{
				InstanceFinder.ServerManager.Broadcast<S2C_Roster>(conn, BuildRoster(), true, (Channel)0);
				FishRuntime byOwner = FishRegistry.GetByOwner(conn);
				if (byOwner != null)
				{
					SendPrivateState(byOwner);
				}
			}
		}

		private static void OnRoster(S2C_Roster msg, Channel channel)
		{
			if (!string.IsNullOrEmpty(msg.Session) && msg.Fish != null && (!_roster.HasValue || !(_roster.Value.Session == msg.Session) || msg.Revision > _roster.Value.Revision))
			{
				if (!_roster.HasValue || _roster.Value.Session != msg.Session)
				{
					MatchController.ResetClient();
					ClearPending();
				}
				_roster = msg;
				_countdownUntil = ((msg.Countdown < 0f) ? (-1f) : (Time.time + msg.Countdown));
				_winnerUntil = Time.time + msg.WinnerSeconds;
				HashSet<int> hashSet = new HashSet<int>();
				FishRosterEntry[] fish = msg.Fish;
				for (int i = 0; i < fish.Length; i++)
				{
					FishRosterEntry fishRosterEntry = fish[i];
					hashSet.Add(fishRosterEntry.BodyId);
				}
				Creature localFishBody = MatchController.LocalFishBody;
				if ((Object)(object)localFishBody != (Object)null && _pendingPrivateStates.ContainsKey(((NetworkBehaviour)localFishBody).ObjectId) && !hashSet.Contains(((NetworkBehaviour)localFishBody).ObjectId))
				{
					Debug.LogWarning((object)("[FishVsHunters] A newer roster (revision " + msg.Revision + ") arrived and discarded our own still-unapplied private state (body=" + ((NetworkBehaviour)localFishBody).ObjectId + ") - bite/movement stay locked until the next one arrives."));
				}
				Prune(_pendingPrivateStates, hashSet);
				Prune(_pendingMutationOffers, hashSet);
				Prune(_pendingSkinOffers, hashSet);
				Prune(_pendingPathOffers, hashSet);
				Prune(_pendingEvolutions, hashSet);
				_pendingBiteVisuals.Clear();
				ProcessPending();
			}
		}

		private static void Prune<T>(Dictionary<int, T> queue, HashSet<int> valid)
		{
			foreach (int item in new List<int>(queue.Keys))
			{
				if (!valid.Contains(item))
				{
					queue.Remove(item);
				}
			}
		}

		private static void OnIslandResidency(S2C_IslandResidency msg, Channel channel)
		{
			IslandRetention.Receive(msg);
		}

		private static void OnPrepareRespawn(S2C_PrepareRespawn msg, Channel channel)
		{
			RoundDirector.PrepareRespawn(msg.OwnerId);
		}

		private static void OnClientState(ClientConnectionStateArgs args)
		{
			//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_0007: Invalid comparison between Unknown and I4
			if ((int)args.ConnectionState == 1)
			{
				ResetClient();
			}
		}

		public static void EnsureRegistered()
		{
			if (_registered && (_clientManager != InstanceFinder.ClientManager || _serverManager != InstanceFinder.ServerManager))
			{
				foreach (Action item in Unregister)
				{
					item();
				}
				Unregister.Clear();
				_registered = false;
				ResetClient();
			}
			if (_registered)
			{
				ProcessPending();
			}
			else
			{
				if ((Object)(object)InstanceFinder.ClientManager == (Object)null || (Object)(object)InstanceFinder.ServerManager == (Object)null)
				{
					return;
				}
				_clientManager = InstanceFinder.ClientManager;
				_serverManager = InstanceFinder.ServerManager;
				ClientManager subscribedClient = _clientManager;
				subscribedClient.OnClientConnectionState += OnClientState;
				Unregister.Add(delegate
				{
					if ((Object)(object)subscribedClient != (Object)null)
					{
						subscribedClient.OnClientConnectionState -= OnClientState;
					}
				});
				ServerManager subscribedServer = _serverManager;
				subscribedServer.OnAuthenticationResult += OnAuthenticationResult;
				Unregister.Add(delegate
				{
					if ((Object)(object)subscribedServer != (Object)null)
					{
						subscribedServer.OnAuthenticationResult -= OnAuthenticationResult;
					}
				});
				RegisterClient<FishEvolutionBroadcast>((Action<FishEvolutionBroadcast, Channel>)OnFishEvolutionBroadcast);
				RegisterClient<S2C_FishPrivateState>((Action<S2C_FishPrivateState, Channel>)OnFishPrivateState);
				RegisterClient<S2C_MutationOffer>((Action<S2C_MutationOffer, Channel>)OnMutationOffer);
				RegisterClient<S2C_SkinOffer>((Action<S2C_SkinOffer, Channel>)OnSkinOffer);
				RegisterClient<S2C_PathOffer>((Action<S2C_PathOffer, Channel>)OnPathOffer);
				RegisterClient<S2C_BiteVisual>((Action<S2C_BiteVisual, Channel>)OnBiteVisual);
				RegisterClient<S2C_Wave>((Action<S2C_Wave, Channel>)OnWaveVisual);
				RegisterClient<S2C_IslandResidency>((Action<S2C_IslandResidency, Channel>)OnIslandResidency);
				RegisterServer<C2S_BecomeFishRequest>((Action<NetworkConnection, C2S_BecomeFishRequest, Channel>)OnBecomeFishRequest);
				RegisterServer<C2S_MutationChoice>((Action<NetworkConnection, C2S_MutationChoice, Channel>)OnMutationChoice);
				RegisterServer<C2S_BiteReport>((Action<NetworkConnection, C2S_BiteReport, Channel>)OnBiteReport);
				RegisterServer<C2S_SkinChoice>((Action<NetworkConnection, C2S_SkinChoice, Channel>)OnSkinChoice);
				RegisterServer<C2S_PathChoice>((Action<NetworkConnection, C2S_PathChoice, Channel>)OnPathChoice);
				RegisterServer<C2S_BiteVisual>((Action<NetworkConnection, C2S_BiteVisual, Channel>)OnBiteVisualRequest);
				RegisterServer<C2S_Wave>((Action<NetworkConnection, C2S_Wave, Channel>)OnWaveRequest);
				RegisterClient<S2C_Roster>((Action<S2C_Roster, Channel>)OnRoster);
				RegisterClient<S2C_PrepareRespawn>((Action<S2C_PrepareRespawn, Channel>)OnPrepareRespawn);
				_registered = true;
				ProcessPending();
			}
		}

		private static void ProcessPending()
		{
			if (_roster.HasValue)
			{
				MatchController.ReconcileRoster(_roster.Value.Fish);
			}
			ProcessControllerQueue(_pendingPrivateStates, delegate(FishController fc, S2C_FishPrivateState msg)
			{
				fc.ApplyPrivateState(msg);
			});
			ProcessControllerQueue(_pendingMutationOffers, delegate(FishController fc, S2C_MutationOffer msg)
			{
				fc.ApplyMutationOffer(msg);
			});
			ProcessControllerQueue(_pendingSkinOffers, delegate(FishController fc, S2C_SkinOffer msg)
			{
				fc.ApplySkinOffer(msg);
			});
			ProcessControllerQueue(_pendingPathOffers, delegate(FishController fc, S2C_PathOffer msg)
			{
				fc.ApplyPathOffer();
			});
			ProcessBodyQueue(_pendingEvolutions, delegate(Creature body, FishEvolutionBroadcast msg)
			{
				//IL_0006: 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)
				((Component)body).transform.localScale = Vector3.one * msg.Scale;
			});
			ProcessBodyQueue(_pendingBiteVisuals, PlayBiteVisual);
		}

		private static void ProcessControllerQueue<T>(Dictionary<int, T> queue, Action<FishController, T> apply)
		{
			if (queue.Count == 0)
			{
				return;
			}
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, T> item in queue)
			{
				Creature val = ResolveBody(item.Key);
				FishController fishController = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<FishController>() : null);
				if (!((Object)(object)fishController == (Object)null))
				{
					apply(fishController, item.Value);
					list.Add(item.Key);
				}
			}
			foreach (int item2 in list)
			{
				queue.Remove(item2);
			}
		}

		private static void ProcessBodyQueue<T>(Dictionary<int, T> queue, Action<Creature, T> apply)
		{
			if (queue.Count == 0)
			{
				return;
			}
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, T> item in queue)
			{
				Creature val = ResolveBody(item.Key);
				if (!((Object)(object)val == (Object)null))
				{
					apply(val, item.Value);
					list.Add(item.Key);
				}
			}
			foreach (int item2 in list)
			{
				queue.Remove(item2);
			}
		}

		internal static Creature ResolveBody(int objectId)
		{
			ClientManager clientManager = InstanceFinder.ClientManager;
			if (((clientManager != null) ? clientManager.Objects : null) == null)
			{
				return null;
			}
			if (!((ManagedObjects)InstanceFinder.ClientManager.Objects).Spawned.TryGetValue(objectId, out var value) || (Object)(object)value == (Object)null)
			{
				return null;
			}
			return ((Component)value).GetComponent<Creature>();
		}

		public static void SendBecomeFishRequest(bool leave)
		{
			if ((Object)(object)InstanceFinder.ClientManager != (Object)null && InstanceFinder.IsClientStarted)
			{
				InstanceFinder.ClientManager.Broadcast<C2S_BecomeFishRequest>(new C2S_BecomeFishRequest
				{
					Leave = leave
				}, (Channel)0);
			}
		}

		public static void SendMutationChoice(byte optionIndex)
		{
			if ((Object)(object)InstanceFinder.ClientManager != (Object)null && InstanceFinder.IsClientStarted)
			{
				InstanceFinder.ClientManager.Broadcast<C2S_MutationChoice>(new C2S_MutationChoice
				{
					OptionIndex = optionIndex
				}, (Channel)0);
			}
		}

		public static void SendBiteReport(int xpAmount, bool wasPreyEaten)
		{
			if ((Object)(object)InstanceFinder.ClientManager != (Object)null && InstanceFinder.IsClientStarted)
			{
				InstanceFinder.ClientManager.Broadcast<C2S_BiteReport>(new C2S_BiteReport
				{
					XpAmount = xpAmount,
					WasPreyEaten = wasPreyEaten
				}, (Channel)0);
			}
		}

		public static void SendBiteVisual()
		{
			if ((Object)(object)InstanceFinder.ClientManager != (Object)null && InstanceFinder.IsClientStarted)
			{
				InstanceFinder.ClientManager.Broadcast<C2S_BiteVisual>(default(C2S_BiteVisual), (Channel)0);
			}
		}

		public static void SendWave()
		{
			if ((Object)(object)InstanceFinder.ClientManager != (Object)null && InstanceFinder.IsClientStarted)
			{
				InstanceFinder.ClientManager.Broadcast<C2S_Wave>(default(C2S_Wave), (Channel)0);
			}
		}

		public static void SendSkinChoice(byte optionIndex)
		{
			if ((Object)(object)InstanceFinder.ClientManager != (Object)null && InstanceFinder.IsClientStarted)
			{
				InstanceFinder.ClientManager.Broadcast<C2S_SkinChoice>(new C2S_SkinChoice
				{
					OptionIndex = optionIndex
				}, (Channel)0);
			}
		}

		public static void SendPathChoice(byte path)
		{
			if ((Object)(object)InstanceFinder.ClientManager != (Object)null && InstanceFinder.IsClientStarted)
			{
				InstanceFinder.ClientManager.Broadcast<C2S_PathChoice>(new C2S_PathChoice
				{
					Path = path
				}, (Channel)0);
			}
		}

		public static void SendEvolution(Creature body, byte level, float scale)
		{
			if (!((Object)(object)body == (Object)null) && InstanceFinder.IsServerStarted)
			{
				InstanceFinder.ServerManager.Broadcast<FishEvolutionBroadcast>(new FishEvolutionBroadcast
				{
					BodyObjectId = ((NetworkBehaviour)body).ObjectId,
					Level = level,
					Scale = scale
				}, true, (Channel)0);
			}
		}

		public static void SendFishAssigned(int bodyObjectId, bool removed)
		{
			BroadcastRoster();
		}

		public static void SendPrivateState(FishRuntime runtime)
		{
			if (!((Object)(object)runtime?.Body == (Object)null) && InstanceFinder.IsServerStarted && !(runtime.OwnerConn == (NetworkConnection)null))
			{
				RoundDirector.Capture(runtime);
				S2C_FishPrivateState s2C_FishPrivateState = new S2C_FishPrivateState
				{
					Stats = FishStatsWire.From(runtime.Stats),
					NextXp = runtime.ThresholdForNextLevel,
					BodyObjectId = ((NetworkBehaviour)runtime.Body).ObjectId,
					Level = runtime.Level,
					Xp = runtime.Xp,
					SkinIndex = (byte)Mathf.Max(0, SkinCatalog.IndexOf(runtime.SkinId)),
					AwaitingSkinChoice = runtime.AwaitingSkinChoice,
					AwaitingMutationChoice = (runtime.PendingChoice != null),
					Path = (byte)runtime.Path,
					AwaitingPathChoice = runtime.AwaitingPathChoice,
					ThickSkin = (byte)runtime.StackOf(MutationId.ThickSkin),
					Armor = (byte)runtime.StackOf(MutationId.Armor),
					Devourer = (byte)runtime.StackOf(MutationId.Devourer),
					Regeneration = (byte)runtime.StackOf(MutationId.Regeneration),
					SharpTeeth = (byte)runtime.StackOf(MutationId.SharpTeeth),
					FastJaw = (byte)runtime.StackOf(MutationId.FastJaw),
					Bleed = (byte)runtime.StackOf(MutationId.Bleed),
					Predator = (byte)runtime.StackOf(MutationId.Predator),
					FastFins = (byte)runtime.StackOf(MutationId.FastFins),
					Maneuverability = (byte)runtime.StackOf(MutationId.Maneuverability),
					Dash = (byte)runtime.StackOf(MutationId.Dash),
					ImprovedDash = (byte)runtime.StackOf(MutationId.ImprovedDash),
					Growth = (byte)runtime.StackOf(MutationId.Growth),
					Gigantism = (byte)runtime.StackOf(MutationId.Gigantism),
					Ram = (byte)runtime.StackOf(MutationId.Ram),
					Sonar = (byte)runtime.StackOf(MutationId.Sonar),
					ImprovedSonar = (byte)runtime.StackOf(MutationId.ImprovedSonar),
					BloodScent = (byte)runtime.StackOf(MutationId.BloodScent),
					TidalWave = (byte)runtime.StackOf(MutationId.TidalWave),
					Manipulation = (byte)runtime.StackOf(MutationId.Manipulation)
				};
				InstanceFinder.ServerManager.Broadcast<S2C_FishPrivateState>(runtime.OwnerConn, s2C_FishPrivateState, true, (Channel)0);
			}
		}

		public static void SendMutationOffer(FishRuntime runtime)
		{
			if (!((Object)(object)runtime?.Body == (Object)null) && runtime.PendingChoice != null && InstanceFinder.IsServerStarted && !(runtime.OwnerConn == (NetworkConnection)null))
			{
				MutationId[] pendingChoice = runtime.PendingChoice;
				InstanceFinder.ServerManager.Broadcast<S2C_MutationOffer>(runtime.OwnerConn, new S2C_MutationOffer
				{
					BodyObjectId = ((NetworkBehaviour)runtime.Body).ObjectId,
					Count = (byte)pendingChoice.Length,
					Option0 = (byte)((pendingChoice.Length != 0) ? pendingChoice[0] : MutationId.ThickSkin),
					Option1 = (byte)((pendingChoice.Length > 1) ? pendingChoice[1] : MutationId.ThickSkin),
					Option2 = (byte)((pendingChoice.Length > 2) ? pendingChoice[2] : MutationId.ThickSkin)
				}, true, (Channel)0);
			}
		}

		public static void SendSkinOffer(FishRuntime runtime)
		{
			if (!((Object)(object)runtime?.Body == (Object)null) && runtime.PendingSkinChoice != null && InstanceFinder.IsServerStarted && !(runtime.OwnerConn == (NetworkConnection)null))
			{
				string[] pendingSkinChoice = runtime.PendingSkinChoice;
				InstanceFinder.ServerManager.Broadcast<S2C_SkinOffer>(runtime.OwnerConn, new S2C_SkinOffer
				{
					BodyObjectId = ((NetworkBehaviour)runtime.Body).ObjectId,
					Count = (byte)Mathf.Min(pendingSkinChoice.Length, 3),
					Option0 = (byte)((pendingSkinChoice.Length != 0) ? ((byte)Mathf.Max(0, SkinCatalog.IndexOf(pendingSkinChoice[0]))) : 0),
					Option1 = (byte)((pendingSkinChoice.Length > 1) ? ((byte)Mathf.Max(0, SkinCatalog.IndexOf(pendingSkinChoice[1]))) : 0),
					Option2 = (byte)((pendingSkinChoice.Length > 2) ? ((byte)Mathf.Max(0, SkinCatalog.IndexOf(pendingSkinChoice[2]))) : 0)
				}, true, (Channel)0);
			}
		}

		public static void SendFishBodySwapped(int oldObjectId, int newObjectId, byte skinIndex)
		{
			BroadcastRoster();
		}

		public static void SendPathOffer(FishRuntime runtime)
		{
			if (!((Object)(object)runtime?.Body == (Object)null) && runtime.PendingPathChoice && InstanceFinder.IsServerStarted && !(runtime.OwnerConn == (NetworkConnection)null))
			{
				InstanceFinder.ServerManager.Broadcast<S2C_PathOffer>(runtime.OwnerConn, new S2C_PathOffer
				{
					BodyObjectId = ((NetworkBehaviour)runtime.Body).ObjectId
				}, true, (Channel)0);
			}
		}

		private static void OnFishEvolutionBroadcast(FishEvolutionBroadcast msg, Channel channel)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Creature val = ResolveBody(msg.BodyObjectId);
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).transform.localScale = Vector3.one * msg.Scale;
			}
			else
			{
				_pendingEvolutions[msg.BodyObjectId] = msg;
			}
		}

		private static void OnFishPrivateState(S2C_FishPrivateState msg, Channel channel)
		{
			Creature val = ResolveBody(msg.BodyObjectId);
			FishController fishController = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<FishController>() : null);
			if ((Object)(object)fishController != (Object)null)
			{
				fishController.ApplyPrivateState(msg);
			}
			else
			{
				_pendingPrivateStates[msg.BodyObjectId] = msg;
			}
		}

		private static void OnMutationOffer(S2C_MutationOffer msg, Channel channel)
		{
			Creature val = ResolveBody(msg.BodyObjectId);
			FishController fishController = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<FishController>() : null);
			if ((Object)(object)fishController != (Object)null)
			{
				fishController.ApplyMutationOffer(msg);
			}
			else
			{
				_pendingMutationOffers[msg.BodyObjectId] = msg;
			}
		}

		private static void OnSkinOffer(S2C_SkinOffer msg, Channel channel)
		{
			Creature val = ResolveBody(msg.BodyObjectId);
			FishController fishController = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<FishController>() : null);
			if ((Object)(object)fishController != (Object)null)
			{
				fishController.ApplySkinOffer(msg);
			}
			else
			{
				_pendingSkinOffers[msg.BodyObjectId] = msg;
			}
		}

		private static void OnPathOffer(S2C_PathOffer msg, Channel channel)
		{
			Creature val = ResolveBody(msg.BodyObjectId);
			FishController fishController = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<FishController>() : null);
			if ((Object)(object)fishController != (Object)null)
			{
				fishController.ApplyPathOffer();
			}
			else
			{
				_pendingPathOffers[msg.BodyObjectId] = msg;
			}
		}

		private static void OnBiteVisual(S2C_BiteVisual msg, Channel channel)
		{
			Creature val = ResolveBody(msg.BodyObjectId);
			if ((Object)(object)val == (Object)null)
			{
				_pendingBiteVisuals[msg.BodyObjectId] = msg;
			}
			else
			{
				PlayBiteVisual(val, msg);
			}
		}

		private static void PlayBiteVisual(Creature body, S2C_BiteVisual msg)
		{
			(((Component)body).GetComponent<FishBiteVisual>() ?? ((Component)body).gameObject.AddComponent<FishBiteVisual>()).Play();
		}

		private static void OnWaveVisual(S2C_Wave msg, Channel channel)
		{
			//IL_001c: 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)
			Creature val = ResolveBody(msg.BodyObjectId);
			if (!((Object)(object)val == (Object)null))
			{
				TidalWaveEffect.Launch(((Component)val).transform.position, ((Component)val).transform.forward, msg.Stack);
			}
		}

		private static void OnBecomeFishRequest(NetworkConnection conn, C2S_BecomeFishRequest msg, Channel channel)
		{
			MatchController.HandleBecomeFishRequest(conn, msg.Leave);
		}

		private static void OnMutationChoice(NetworkConnection conn, C2S_MutationChoice msg, Channel channel)
		{
			MatchController.HandleMutationChoice(conn, msg.OptionIndex);
		}

		private static void OnBiteReport(NetworkConnection conn, C2S_BiteReport msg, Channel channel)
		{
			MatchController.HandleBiteReport(conn, msg.XpAmount, msg.WasPreyEaten);
		}

		private static void OnSkinChoice(NetworkConnection conn, C2S_SkinChoice msg, Channel channel)
		{
			MatchController.HandleSkinChoice(conn, msg.OptionIndex);
		}

		private static void OnPathChoice(NetworkConnection conn, C2S_PathChoice msg, Channel channel)
		{
			MatchController.HandlePathChoice(conn, msg.Path);
		}

		private static void OnBiteVisualRequest(NetworkConnection conn, C2S_BiteVisual msg, Channel channel)
		{
			FishRuntime byOwner = FishRegistry.GetByOwner(conn);
			if ((Object)(object)byOwner?.Body != (Object)null)
			{
				InstanceFinder.ServerManager.Broadcast<S2C_BiteVisual>(new S2C_BiteVisual
				{
					BodyObjectId = ((NetworkBehaviour)byOwner.Body).ObjectId
				}, true, (Channel)0);
			}
		}

		private static void OnWaveRequest(NetworkConnection conn, C2S_Wave msg, Channel channel)
		{
			//IL_00b2: 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_00c7: 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_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: 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_0117: Unknown result type (might be due to invalid IL or missing references)
			FishRuntime byOwner = FishRegistry.GetByOwner(conn);
			int num = byOwner?.StackOf(MutationId.TidalWave) ?? 0;
			if (byOwner == null || !byOwner.Alive || byOwner.Path != EvolutionPath.Primal || num <= 0 || Time.time < byOwner.NextWaveTime)
			{
				return;
			}
			byOwner.NextWaveTime = Time.time + 12f;
			float num2 = 12f + (float)num * 4f;
			int num3 = 15 + num * 10;
			foreach (Player alivePlayer in PlayerManager.AlivePlayers)
			{
				if (!((Object)(object)alivePlayer == (Object)null) && !(((NetworkBehaviour)alivePlayer).Owner == conn) && FishRegistry.GetByOwner(((NetworkBehaviour)alivePlayer).Owner) == null)
				{
					Vector3 val = alivePlayer.Transform.position - ((Component)byOwner.Body).transform.position;
					if (!(((Vector3)(ref val)).sqrMagnitude > num2 * num2))
					{
						Server.Instance.HitPlayer(alivePlayer, num3, ((Vector3)(ref val)).normalized * (12f + (float)num * 4f) + Vector3.up * 5f, alivePlayer.Transform.position, (byte)3, (Player)null);
					}
				}
			}
			InstanceFinder.ServerManager.Broadcast<S2C_Wave>(new S2C_Wave
			{
				BodyObjectId = ((NetworkBehaviour)byOwner.Body).ObjectId,
				Stack = (byte)num
			}, true, (Channel)0);
			Debug.Log((object)$"[FishVsHunters] TIDAL WAVE conn#{conn.ClientId}: stack={num}, radius={num2}, damage={num3}.");
		}
	}
	public struct FishRosterEntry
	{
		public int OwnerId;

		public int BodyId;

		public bool Dead;

		public float Scale;

		public int MaxHp;

		public float Mass;
	}
	public struct S2C_Roster : IBroadcast
	{
		public string Session;

		public int Revision;

		public int Round;

		public bool AutoRestart;

		public bool RoundLocked;

		public float Countdown;

		public byte Winner;

		public float WinnerSeconds;

		public FishRosterEntry[] Fish;
	}
	public struct S2C_PrepareRespawn : IBroadcast
	{
		public int OwnerId;
	}
	internal static class RosterWire
	{
		internal static void Register()
		{
			GenericWriter<S2C_Roster>.SetWrite((Action<Writer, S2C_Roster>)Write);
			GenericReader<S2C_Roster>.SetRead((Func<Reader, S2C_Roster>)Read);
			GenericWriter<S2C_PrepareRespawn>.SetWrite((Action<Writer, S2C_PrepareRespawn>)delegate(Writer w, S2C_PrepareRespawn v)
			{
				w.WriteInt32(v.OwnerId);
			});
			GenericReader<S2C_PrepareRespawn>.SetRead((Func<Reader, S2C_PrepareRespawn>)((Reader r) => new S2C_PrepareRespawn
			{
				OwnerId = r.ReadInt32()
			}));
		}

		internal static void Write(Writer w, S2C_Roster v)
		{
			w.WriteString(v.Session);
			w.WriteInt32(v.Revision);
			w.WriteInt32(v.Round);
			w.WriteBoolean(v.AutoRestart);
			w.WriteSingle(v.Countdown);
			w.WriteBoolean(v.RoundLocked);
			w.WriteUInt8Unpacked(v.Winner);
			w.WriteSingle(v.WinnerSeconds);
			w.WriteInt32(v.Fish.Length);
			FishRosterEntry[] fish = v.Fish;
			for (int i = 0; i < fish.Length; i++)
			{
				FishRosterEntry fishRosterEntry = fish[i];
				w.WriteInt32(fishRosterEntry.OwnerId);
				w.WriteInt32(fishRosterEntry.BodyId);
				w.WriteBoolean(fishRosterEntry.Dead);
				w.WriteSingle(fishRosterEntry.Scale);
				w.WriteInt32(fishRosterEntry.MaxHp);
				w.WriteSingle(fishRosterEntry.Mass);
			}
		}

		internal static S2C_Roster Read(Reader r)
		{
			S2C_Roster result = new S2C_Roster
			{
				Session = r.ReadStringAllocated(),
				Revision = r.ReadInt32(),
				Round = r.ReadInt32(),
				AutoRestart = r.ReadBoolean(),
				Countdown = r.ReadSingle()
			};
			result.RoundLocked = r.ReadBoolean();
			result.Winner = r.ReadUInt8Unpacked();
			result.WinnerSeconds = r.ReadSingle();
			int num = r.ReadInt32();
			if (num < 0 || num > 128)
			{
				throw new InvalidDataException("Invalid fish roster length.");
			}
			result.Fish = new FishRosterEntry[num];
			for (int i = 0; i < num; i++)
			{
				result.Fish[i] = new FishRosterEntry
				{
					OwnerId = r.ReadInt32(),
					BodyId = r.ReadInt32(),
					Dead = r.ReadBoolean(),
					Scale = r.ReadSingle(),
					MaxHp = r.ReadInt32(),
					Mass = r.ReadSingle()
				};
			}
			return result;
		}
	}
}
namespace FishVsHunters.match
{
	internal struct CalculatedFishStats
	{
		public int Level;

		public float MaxHp;

		public float ArmorPercent;

		public float BiteDamage;

		public float BiteCooldown;

		public float BiteRange;

		public float BiteRadius;

		public float SwimSpeed;

		public float TurnSpeedDegPerSec;

		public float Acceleration;

		public float Scale;

		public float Mass;

		public float MassMultiplier;

		public bool DashUnlocked;

		public float DashCooldown;

		public float DashForce;

		public bool SonarUnlocked;

		public float SonarCooldown;

		public float SonarDuration;

		public bool RamUnlocked;

		public bool BleedUnlocked;

		public float BleedDamagePerTick;

		public bool PredatorUnlocked;

		public float PredatorBonusDamagePercent;

		public bool DevourerUnlocked;

		public float DevourerHealPercent;

		public bool RegenerationUnlocked;

		public float RegenerationHpPerTick;

		public bool BloodScentUnlocked;

		public static int StackOf(IReadOnlyDictionary<MutationId, int> stacks, MutationId id)
		{
			if (stacks == null || !stacks.TryGetValue(id, out var value))
			{
				return 0;
			}
			return value;
		}

		private static SkinBaseStats FallbackBand()
		{
			return new SkinBaseStats
			{
				Scale = 1f,
				MaxHp = 40f,
				BiteDamage = 12f,
				SwimSpeed = Config.SwimSpeed.Value,
				ArmorPercent = 0f,
				BiteRange = Config.BiteForwardOffset.Value,
				Mass = SkinCatalog.BaselineMass,
				TurnSpeedDegPerSec = Config.TurnSpeedDegPerSec.Value
			};
		}

		public static CalculatedFishStats Compute(SkinDefinition skin, int level, IReadOnlyDictionary<MutationId, int> stacks)
		{
			level = Mathf.Clamp(level, 1, 100);
			SkinBaseStats skinBaseStats = skin?.Evaluate(level) ?? FallbackBand();
			int num = StackOf(stacks, MutationId.ThickSkin);
			int num2 = StackOf(stacks, MutationId.Armor);
			int num3 = StackOf(stacks, MutationId.Devourer);
			int num4 = StackOf(stacks, MutationId.Regeneration);
			int num5 = StackOf(stacks, MutationId.SharpTeeth);
			int num6 = StackOf(stacks, MutationId.FastJaw);
			int num7 = StackOf(stacks, MutationId.Bleed);
			int num8 = StackOf(stacks, MutationId.Predator);
			int num9 = StackOf(stacks, MutationId.FastFins);
			int num10 = StackOf(stacks, MutationId.Maneuverability);
			int num11 = StackOf(stacks, MutationId.Dash);
			int num12 = StackOf(stacks, MutationId.ImprovedDash);
			int num13 = StackOf(stacks, MutationId.Growth);
			int num14 = StackOf(stacks, MutationId.Gigantism);
			int num15 = StackOf(stacks, MutationId.Ram);
			int num16 = StackOf(stacks, MutationId.Sonar);
			int num17 = StackOf(stacks, MutationId.ImprovedSonar);
			int num18 = StackOf(stacks, MutationId.BloodScent);
			float num19 = skinBaseStats.Scale + (float)num13 * Config.GrowthScalePerStack.Value + (float)num14 * Config.GigantismScaleBonus.Value;
			float num20 = skinBaseStats.TurnSpeedDegPerSec + (float)num10 * Config.ManeuverabilityTurnPerStack.Value - (float)num13 * Config.GrowthTurnPenaltyPerStack.Value - (float)num14 * Config.GigantismTurnPenalty.Value;
			float num21 = skinBaseStats.ArmorPercent + (float)num2 * Config.ArmorPercentPerStack.Value;
			CalculatedFishStats result = new CalculatedFishStats
			{
				Level = level,
				MaxHp = skinBaseStats.MaxHp + (float)num * Config.ThickSkinHpPerStack.Value,
				ArmorPercent = Mathf.Min(num21, Config.ArmorCapPercent.Value),
				BiteDamage = skinBaseStats.BiteDamage + (float)num5 * Config.SharpTeethDamagePerStack.Value,
				BiteCooldown = Mathf.Max(Config.BiteCooldownMinimum.Value, Config.BiteCooldown.Value - (float)num6 * Config.FastJawCooldownReductionPerStack.Value),
				BiteRange = skinBaseStats.BiteRange * (1f + (float)num13 * 0.15f + (float)num14 * 0.3f),
				BiteRadius = Config.BiteRadius.Value,
				SwimSpeed = Mathf.Max(1f, skinBaseStats.SwimSpeed + (float)num9 * Config.FastFinsSpeedPerStack.Value),
				TurnSpeedDegPerSec = Mathf.Max(30f, num20),
				Acceleration = Config.SwimAcceleration.Value * Mathf.Clamp(1f / Mathf.Max(1f, Mathf.Sqrt(Mathf.Max(0.1f, num19))), 0.3f, 1f),
				Scale = Mathf.Max(0.1f, num19),
				Mass = Mathf.Max(0.1f, skinBaseStats.Mass),
				MassMultiplier = 1f,
				DashUnlocked = (num11 > 0),
				DashCooldown = Mathf.Max(0.5f, Config.DashCooldown.Value - (float)num12 * Config.ImprovedDashCooldownReductionPerStack.Value),
				DashForce = Config.DashForce.Value,
				SonarUnlocked = (num16 > 0),
				SonarCooldown = Mathf.Max(2f, Config.SonarCooldown.Value - (float)num17 * Config.ImprovedSonarCooldownReductionPerStack.Value),
				SonarDuration = Config.SonarDuration.Value + (float)num17 * Config.ImprovedSonarDurationBonusPerStack.Value,
				RamUnlocked = (num15 > 0),
				BleedUnlocked = (num7 > 0),
				BleedDamagePerTick = (float)num7 * Config.BleedDamagePerTick.Value,
				PredatorUnlocked = (num8 > 0),
				PredatorBonusDamagePercent = (float)num8 * Config.PredatorBonusDamagePercentPerStack.Value,
				DevourerUnlocked = (num3 > 0),
				DevourerHealPercent = (float)num3 * Config.DevourerHealPercentPerStack.Value,
				RegenerationUnlocked = (num4 > 0 && level >= Config.RegenerationMinLevel.Value),
				RegenerationHpPerTick = (float)num4 * Config.Regeneration