Decompiled source of GreedySeagulls v1.0.0

BepInEx/plugins/GreedySeagulls.dll

Decompiled 31 minutes ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FishNet;
using FishNet.Broadcast;
using FishNet.Connection;
using FishNet.Object;
using FishNet.Serializing;
using FishNet.Transporting;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("GreedySeagulls")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("GreedySeagulls")]
[assembly: AssemblyTitle("GreedySeagulls")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GreedySeagulls
{
	public static class Birds
	{
		private static readonly List<Bird> _all = new List<Bird>();

		public static IReadOnlyList<Bird> All => _all;

		public static void Add(Bird bird)
		{
			if ((Object)(object)bird != (Object)null && !_all.Contains(bird))
			{
				_all.Add(bird);
			}
		}

		public static void Remove(Bird bird)
		{
			if (!((Object)(object)bird == (Object)null))
			{
				_all.Remove(bird);
				Swarm.Forget(bird);
				BoatLift.Forget(bird);
				GunBird.Forget(bird);
			}
		}

		public static void Clear()
		{
			_all.Clear();
		}

		public static void Prune()
		{
			for (int num = _all.Count - 1; num >= 0; num--)
			{
				Bird val = _all[num];
				if (!((Object)(object)val != (Object)null))
				{
					_all.RemoveAt(num);
					Swarm.Forget(val);
					BoatLift.Forget(val);
					GunBird.Forget(val);
				}
			}
		}
	}
	public static class BirdSpawner
	{
		private const float DebugSpawnDistance = 40f;

		public static Bird FindTemplate()
		{
			foreach (Bird item in Birds.All)
			{
				if ((Object)(object)item != (Object)null && !((Creature)item).IsDead)
				{
					return item;
				}
			}
			foreach (Bird item2 in Birds.All)
			{
				if ((Object)(object)item2 != (Object)null)
				{
					return item2;
				}
			}
			Bird[] array = Resources.FindObjectsOfTypeAll<Bird>();
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i] != (Object)null)
				{
					return array[i];
				}
			}
			return null;
		}

		public static int CountFree()
		{
			int num = 0;
			foreach (Bird item in Birds.All)
			{
				if ((Object)(object)item != (Object)null && !((Creature)item).IsDead && (Object)(object)item.CaughtItem == (Object)null && !BoatLift.IsCrew(item))
				{
					num++;
				}
			}
			return num;
		}

		public static int SpawnRing(Bird template, Vector3 center, float flyHeight, int count, float minDistance, float maxDistance, float heightJitter, List<NetworkObject> track)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)template == (Object)null || count <= 0)
			{
				return 0;
			}
			float num = 360f / (float)count;
			int num2 = 0;
			for (int i = 0; i < count; i++)
			{
				try
				{
					float num3 = num * (float)i + Random.Range((0f - num) * 0.35f, num * 0.35f);
					float num4 = Random.Range(minDistance, maxDistance);
					Vector3 val = Quaternion.Euler(0f, num3, 0f) * Vector3.forward * num4;
					Vector3 val2 = center + val;
					val2.y = flyHeight + Random.Range(0f - heightJitter, heightJitter);
					Vector3 val3 = center - val2;
					val3.y = 0f;
					if (((Vector3)(ref val3)).sqrMagnitude < 0.01f)
					{
						val3 = Vector3.forward;
					}
					GameObject val4 = Object.Instantiate<GameObject>(((Component)template).gameObject, val2, Quaternion.LookRotation(((Vector3)(ref val3)).normalized));
					NetworkObject component = val4.GetComponent<NetworkObject>();
					if ((Object)(object)component == (Object)null)
					{
						Object.Destroy((Object)(object)val4);
						continue;
					}
					InstanceFinder.ServerManager.Spawn(component, (NetworkConnection)null, default(Scene));
					if (!component.IsSpawned)
					{
						Object.Destroy((Object)(object)val4);
						continue;
					}
					track?.Add(component);
					num2++;
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Could not spawn a seagull: " + ex.Message));
					break;
				}
			}
			return num2;
		}

		public static int EnsureFreeBirds(int required, Vector3 center)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			int num = CountFree();
			if (num >= required)
			{
				return 0;
			}
			Bird val = FindTemplate();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"There are no seagulls anywhere to copy, so none can be spawned.");
				return 0;
			}
			int count = required - num;
			float num2 = 40f;
			int num3 = SpawnRing(val, center, val.FlyHeigth, count, num2 * 0.5f, num2, 3f, null);
			Plugin.Log.LogInfo((object)$"{num} free seagull(s) present, spawned {num3} more to reach {required}.");
			return num3;
		}
	}
	public static class BoatLift
	{
		private enum Stage
		{
			Idle,
			Gathering,
			Carrying
		}

		private class CrewState
		{
			public int Index;

			public bool InPosition;
		}

		private static readonly Dictionary<Bird, CrewState> _crew = new Dictionary<Bird, CrewState>();

		private static Stage _stage = Stage.Idle;

		private static float _nextAllowedTime;

		private static float _nextCheckTime;

		private static float _stageDeadline;

		private static Vector3 _orbitCenter;

		private static float _orbitRadius;

		private static float _orbitSign = 1f;

		public static bool Active => _stage != Stage.Idle;

		public static bool IsCrew(Bird bird)
		{
			if ((Object)(object)bird != (Object)null)
			{
				return _crew.ContainsKey(bird);
			}
			return false;
		}

		public static void Reset()
		{
			_crew.Clear();
			_stage = Stage.Idle;
			_nextAllowedTime = 0f;
			_nextCheckTime = 0f;
			_stageDeadline = 0f;
		}

		public static void Forget(Bird bird)
		{
			if ((Object)(object)bird != (Object)null && _crew.Remove(bird) && _stage != Stage.Idle)
			{
				Plugin.Log.LogInfo((object)"A seagull carrying the boat is gone.");
				if (_crew.Count < Plugin.BoatLiftRequiredBirds.Value)
				{
					Release("the crew got too thin");
				}
			}
		}

		public static void ForceStart()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			_nextAllowedTime = 0f;
			Boat boat = BoatManager.Boat;
			if ((Object)(object)boat == (Object)null || (Object)(object)boat.HiddenPhysicsRig == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Cannot lift the boat: there is no boat.");
				return;
			}
			BirdSpawner.EnsureFreeBirds(Mathf.Max(1, Plugin.BoatLiftRequiredBirds.Value), boat.HiddenPhysicsRig.position);
			if (!TryBegin())
			{
				Plugin.Log.LogWarning((object)"Cannot lift the boat right now, even after trying to spawn seagulls.");
			}
		}

		public static void Tick()
		{
			if (_stage == Stage.Idle)
			{
				if (Plugin.BoatLiftEnabled.Value && !Swarm.Active && !(Time.time < _nextCheckTime))
				{
					_nextCheckTime = Time.time + Plugin.BoatLiftCheckInterval.Value;
					if (!(Time.time < _nextAllowedTime) && !(Random.value > Plugin.BoatLiftChance.Value))
					{
						TryBegin();
					}
				}
				return;
			}
			Boat boat = BoatManager.Boat;
			if ((Object)(object)boat == (Object)null || (Object)(object)boat.HiddenPhysicsRig == (Object)null)
			{
				Release("the boat is gone");
				return;
			}
			PruneCrew();
			if (_crew.Count < Plugin.BoatLiftRequiredBirds.Value)
			{
				Release("the crew got too thin");
			}
			else if (_stage == Stage.Gathering)
			{
				if (AllInPosition(boat))
				{
					_stage = Stage.Carrying;
					_stageDeadline = Time.time + Plugin.BoatLiftDuration.Value;
					BeginOrbit(boat);
					Plugin.Log.LogInfo((object)$"{_crew.Count} seagulls have the boat and are hauling it into a circuit of the island at {_orbitRadius:F0}m.");
				}
				else if (Time.time >= _stageDeadline)
				{
					Release("they could not get a grip in time");
				}
			}
			else if (Time.time >= _stageDeadline)
			{
				Release("they got bored");
			}
		}

		private static bool TryBegin()
		{
			if (Swarm.Active)
			{
				return false;
			}
			Boat boat = BoatManager.Boat;
			if ((Object)(object)boat == (Object)null || (Object)(object)boat.HiddenPhysicsRig == (Object)null)
			{
				return false;
			}
			List<Bird> list = new List<Bird>();
			foreach (Bird item in Birds.All)
			{
				if ((Object)(object)item != (Object)null && !((Creature)item).IsDead && (Object)(object)item.CaughtItem == (Object)null)
				{
					list.Add(item);
				}
			}
			int num = Mathf.Max(1, Plugin.BoatLiftRequiredBirds.Value);
			if (list.Count < num)
			{
				return false;
			}
			int num2 = Mathf.Min(list.Count, Mathf.Max(num, Plugin.BoatLiftMaxBirds.Value));
			_crew.Clear();
			for (int i = 0; i < num2; i++)
			{
				_crew[list[i]] = new CrewState
				{
					Index = i,
					InPosition = false
				};
				list[i].SetAttackingFood((Item)null);
			}
			_stage = Stage.Gathering;
			_stageDeadline = Time.time + Plugin.BoatLiftGatherTimeout.Value;
			_nextAllowedTime = Time.time + Plugin.BoatLiftCooldownMinutes.Value * 60f;
			Plugin.Log.LogInfo((object)$"{_crew.Count} seagulls are moving in on the boat.");
			return true;
		}

		private static void PruneCrew()
		{
			List<Bird> list = null;
			foreach (KeyValuePair<Bird, CrewState> item in _crew)
			{
				if ((Object)(object)item.Key == (Object)null || ((Creature)item.Key).IsDead)
				{
					if (list == null)
					{
						list = new List<Bird>();
					}
					list.Add(item.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (Bird item2 in list)
			{
				_crew.Remove(item2);
			}
		}

		private static bool AllInPosition(Boat boat)
		{
			foreach (KeyValuePair<Bird, CrewState> item in _crew)
			{
				if (!item.Value.InPosition)
				{
					return false;
				}
			}
			return true;
		}

		private static Vector3 GripPoint(Boat boat, int index)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Max(1, _crew.Count);
			float num2 = 360f / (float)num * (float)index * (MathF.PI / 180f);
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(Mathf.Sin(num2) * Plugin.BoatLiftRadiusX.Value, Plugin.BoatLiftGripHeight.Value, Mathf.Cos(num2) * Plugin.BoatLiftRadiusZ.Value);
			return ((Component)boat.HiddenPhysicsRig).transform.TransformPoint(val);
		}

		public static void SimulateCrewBird(Bird bird)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			Boat boat = BoatManager.Boat;
			if ((Object)(object)boat == (Object)null || (Object)(object)boat.HiddenPhysicsRig == (Object)null || !_crew.TryGetValue(bird, out var value))
			{
				return;
			}
			Vector3 val = GripPoint(boat, value.Index);
			Vector3 position = ((Component)bird).transform.position;
			float num = Vector3.Distance(position, val);
			if (!value.InPosition && num <= Plugin.BoatLiftGripDistance.Value)
			{
				value.InPosition = true;
			}
			if (value.InPosition || _stage == Stage.Carrying)
			{
				((Component)bird).transform.position = Vector3.MoveTowards(position, val, Plugin.BoatLiftHoldSpeed.Value * Time.deltaTime);
				Vector3 val2 = val - ((Component)boat.HiddenPhysicsRig).transform.position;
				val2.y = 0f;
				if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
				{
					val2 = ((Component)boat.HiddenPhysicsRig).transform.forward;
				}
				((Component)bird).transform.forward = ((Vector3)(ref val2)).normalized;
				bird.SetSpeed(0f);
				bird.SetAnimState((byte)4);
			}
			else
			{
				float num2 = Mathf.Min(Plugin.BoatLiftApproachSpeed.Value, num * 2f + 1f);
				((Component)bird).transform.position = Vector3.MoveTowards(position, val, num2 * Time.deltaTime);
				Vector3 val3 = val - ((Component)bird).transform.position;
				if (((Vector3)(ref val3)).sqrMagnitude > 0.0001f)
				{
					((Component)bird).transform.forward = ((Vector3)(ref val3)).normalized;
				}
				bird.SetSpeed(num2);
				bird.SetAnimState((byte)2);
			}
		}

		private static Vector3 OrbitCenter()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Island.CurIsland != (Object)null)
			{
				return Island.IslandPos;
			}
			if ((Object)(object)Player.LocalPlayer != (Object)null)
			{
				return Player.LocalPlayer.Transform.position;
			}
			return Vector3.zero;
		}

		private static void BeginOrbit(Boat boat)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			_orbitCenter = OrbitCenter();
			_orbitSign = ((Random.value < 0.5f) ? (-1f) : 1f);
			Vector3 val = boat.HiddenPhysicsRig.position - _orbitCenter;
			val.y = 0f;
			_orbitRadius = Mathf.Clamp(((Vector3)(ref val)).magnitude, Plugin.BoatLiftOrbitRadiusMin.Value, Plugin.BoatLiftOrbitRadiusMax.Value);
		}

		public static void DriveBoat()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			if (_stage != Stage.Carrying)
			{
				return;
			}
			Boat boat = BoatManager.Boat;
			if (!((Object)(object)boat == (Object)null) && !((Object)(object)boat.HiddenPhysicsRig == (Object)null))
			{
				Rigidbody hiddenPhysicsRig = boat.HiddenPhysicsRig;
				float num = WaterManager.WaterHeight + Plugin.BoatLiftHeight.Value - hiddenPhysicsRig.position.y;
				float value = Plugin.BoatLiftRiseSpeed.Value;
				float y = Mathf.Clamp(num, (0f - value) * 0.5f, value);
				float num2 = Mathf.Clamp01(1f - Mathf.Abs(num) / Mathf.Max(1f, Plugin.BoatLiftHeight.Value));
				_orbitCenter = OrbitCenter();
				Vector3 val = hiddenPhysicsRig.position - _orbitCenter;
				val.y = 0f;
				float magnitude = ((Vector3)(ref val)).magnitude;
				Vector3 val2 = ((magnitude < 0.01f) ? Vector3.forward : (val / magnitude));
				Vector3 val3 = Vector3.Cross(Vector3.up, val2) * _orbitSign;
				float num3 = Mathf.Clamp((_orbitRadius - magnitude) * Plugin.BoatLiftOrbitCorrection.Value, -1f, 1f);
				Vector3 val4 = val3 + val2 * num3;
				Vector3 linearVelocity = ((Vector3)(ref val4)).normalized * (Plugin.BoatLiftCruiseSpeed.Value * num2);
				linearVelocity.y = y;
				hiddenPhysicsRig.linearVelocity = linearVelocity;
				Quaternion rotation = hiddenPhysicsRig.rotation;
				Quaternion val5 = Quaternion.Euler(0f, ((Quaternion)(ref rotation)).eulerAngles.y, 0f);
				Vector3 angularVelocity = DazedUtils.GetAngularVelocityToTarget(hiddenPhysicsRig.rotation, val5) * Plugin.BoatLiftLevelStrength.Value;
				float value2 = Plugin.BoatLiftMaxLevelSpeed.Value;
				if (((Vector3)(ref angularVelocity)).sqrMagnitude > value2 * value2)
				{
					angularVelocity = ((Vector3)(ref angularVelocity)).normalized * value2;
				}
				hiddenPhysicsRig.angularVelocity = angularVelocity;
			}
		}

		private static void Release(string reason)
		{
			if (_stage == Stage.Idle)
			{
				return;
			}
			foreach (KeyValuePair<Bird, CrewState> item in _crew)
			{
				if ((Object)(object)item.Key != (Object)null)
				{
					item.Key.SetSpeed(0f);
				}
			}
			_crew.Clear();
			_stage = Stage.Idle;
			_nextCheckTime = Time.time + Plugin.BoatLiftCheckInterval.Value;
			Plugin.Log.LogInfo((object)("The seagulls dropped the boat: " + reason + "."));
		}
	}
	public static class ForceSteal
	{
		public static void Trigger()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.LocalPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				Plugin.Log.LogWarning((object)"No local player.");
				return;
			}
			Item val = (((Object)(object)localPlayer.Holding != (Object)null) ? localPlayer.Holding.HeldItem : null);
			string text = "your hands";
			if ((Object)(object)val == (Object)null || ((NetworkBehaviour)val).IsDeinitializing || val.IsDestroying)
			{
				val = NearestGroundTool(localPlayer.Transform.position);
				text = "the ground";
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogInfo((object)"Nothing to steal: your hands are empty and nothing holdable is lying nearby.");
				return;
			}
			Bird val2 = NearestFreeBird(((Component)val).transform.position);
			if ((Object)(object)val2 == (Object)null)
			{
				BirdSpawner.EnsureFreeBirds(1, ((Component)val).transform.position);
				val2 = NearestFreeBird(((Component)val).transform.position);
			}
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"No free seagull available to send, and none could be spawned.");
				return;
			}
			val2.SetAttackingFood(val);
			Plugin.Log.LogInfo((object)("Sent a seagull after '" + val.GetName() + "' from " + text + "."));
		}

		private static Item NearestGroundTool(Vector3 from)
		{
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			Item result = null;
			float num = float.MaxValue;
			HashSet<Item> hashSet = new HashSet<Item>();
			foreach (KeyValuePair<Transform, Item> item in ItemManager.Items)
			{
				Item value = item.Value;
				if ((Object)(object)value == (Object)null || !hashSet.Add(value))
				{
					continue;
				}
				Targeting.Kind kind = Targeting.Categorize(value);
				if ((kind == Targeting.Kind.Tool || kind == Targeting.Kind.Holdable) && !((NetworkBehaviour)value).IsDeinitializing && !value.IsDestroying && value.IsInteractable && !((Object)(object)value.BirdHolder != (Object)null) && !((Object)(object)value.Bird != (Object)null) && !((Object)(object)value.SyncedHolder != (Object)null) && !((Object)(object)value.Holder != (Object)null))
				{
					float num2 = Vector3.Distance(from, ((Component)value).transform.position);
					if (num2 < num)
					{
						num = num2;
						result = value;
					}
				}
			}
			return result;
		}

		private static Bird NearestFreeBird(Vector3 from)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			Bird result = null;
			float num = float.MaxValue;
			foreach (Bird item in Birds.All)
			{
				if (!((Object)(object)item == (Object)null) && !((Creature)item).IsDead && !((Object)(object)item.CaughtItem != (Object)null) && !BoatLift.IsCrew(item))
				{
					float num2 = Vector3.Distance(from, ((Component)item).transform.position);
					if (num2 < num)
					{
						num = num2;
						result = item;
					}
				}
			}
			return result;
		}
	}
	public static class GunBird
	{
		private static readonly Dictionary<Bird, float> _nextShot = new Dictionary<Bird, float>();

		public static void Clear()
		{
			_nextShot.Clear();
		}

		public static void Forget(Bird bird)
		{
			if ((Object)(object)bird != (Object)null)
			{
				_nextShot.Remove(bird);
			}
		}

		public static void Tick(IEnumerable<Bird> birds)
		{
			if (!Plugin.StolenGunsFire.Value || (Object)(object)Player.LocalPlayer == (Object)null)
			{
				return;
			}
			foreach (Bird bird in birds)
			{
				if ((Object)(object)bird == (Object)null || ((Creature)bird).IsDead)
				{
					continue;
				}
				Item caughtItem = bird.CaughtItem;
				Weapon val = (((Object)(object)caughtItem != (Object)null) ? caughtItem.Weapon : null);
				if (!((Object)(object)val == (Object)null))
				{
					if (!_nextShot.TryGetValue(bird, out var value))
					{
						_nextShot[bird] = Time.time + RandomInterval();
					}
					else if (!(Time.time < value))
					{
						_nextShot[bird] = Time.time + RandomInterval();
						FireOnce(val);
					}
				}
			}
		}

		private static float RandomInterval()
		{
			float value = Plugin.GunFireIntervalMin.Value;
			float num = Mathf.Max(value, Plugin.GunFireIntervalMax.Value);
			return Random.Range(value, num);
		}

		private static void FireOnce(Weapon weapon)
		{
			//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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			Attachments attachments = weapon.Attachments;
			if ((Object)(object)attachments == (Object)null)
			{
				return;
			}
			Transform firePoint = attachments.FirePoint;
			if (!((Object)(object)firePoint == (Object)null))
			{
				WeaponInfo weaponInfo = Refl.GetWeaponInfo(weapon);
				if (weaponInfo != null && !((Object)(object)ProjectileManager.Instance == (Object)null))
				{
					Vector3 val = firePoint.forward + Random.insideUnitSphere * Plugin.GunSpread.Value;
					((Vector3)(ref val)).Normalize();
					ProjectileManager.Instance.AddProjectile(Player.LocalPlayer, weaponInfo, true, firePoint.position, val * weaponInfo.ProjectileForce, 0u, 0u, true);
					weapon.ShootEffects(false);
				}
			}
		}
	}
	public static class HeldTargetFix
	{
		public static bool GetFlyDirection(Bird bird, ref Vector3 result)
		{
			//IL_0044: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)bird == (Object)null)
			{
				return true;
			}
			Item attackingItem = bird.AttackingItem;
			if ((Object)(object)attackingItem == (Object)null)
			{
				return true;
			}
			if (!((Object)(object)attackingItem.Holder != (Object)null) && !((Object)(object)attackingItem.SyncedHolder != (Object)null))
			{
				return true;
			}
			Vector3 val = ((Component)attackingItem).transform.position - ((Component)bird).transform.position;
			if (((NetworkBehaviour)attackingItem).IsDeinitializing || attackingItem.IsDestroying || (Object)(object)attackingItem.BirdHolder != (Object)null || !attackingItem.IsInteractable)
			{
				bird.SetAttackingFood((Item)null);
				return true;
			}
			if (Physics.Raycast(((Component)bird).transform.position, val, Mathf.Max(0f, ((Vector3)(ref val)).magnitude - 0.15f), LayerMask.op_Implicit(GameInfo.LevelLayer)))
			{
				return true;
			}
			if (Plugin.RequireOpenSkyForHandSteal.Value && Physics.Raycast(((Component)attackingItem).transform.position, Vector3.up, 10f, LayerMask.op_Implicit(GameInfo.LevelLayer)))
			{
				return true;
			}
			result = val;
			return false;
		}
	}
	public struct SwarmBarBroadcast : IBroadcast
	{
		public bool Active;

		public int Current;

		public int Max;

		public uint SpawnTick;

		public uint TotalTicks;
	}
	public static class Net
	{
		private static bool _serializersRegistered;

		private static bool _clientRegistered;

		public static void RegisterSerializers()
		{
			if (!_serializersRegistered)
			{
				_serializersRegistered = true;
				GenericWriter<SwarmBarBroadcast>.SetWrite((Action<Writer, SwarmBarBroadcast>)delegate(Writer w, SwarmBarBroadcast v)
				{
					w.WriteBoolean(v.Active);
					w.WriteInt32(v.Current);
					w.WriteInt32(v.Max);
					w.WriteUInt32(v.SpawnTick);
					w.WriteUInt32(v.TotalTicks);
				});
				GenericReader<SwarmBarBroadcast>.SetRead((Func<Reader, SwarmBarBroadcast>)((Reader r) => new SwarmBarBroadcast
				{
					Active = r.ReadBoolean(),
					Current = r.ReadInt32(),
					Max = r.ReadInt32(),
					SpawnTick = r.ReadUInt32(),
					TotalTicks = r.ReadUInt32()
				}));
			}
		}

		public static void TryRegisterHandlers()
		{
			if (!((Object)(object)InstanceFinder.NetworkManager == (Object)null))
			{
				RegisterSerializers();
				if (!_clientRegistered && (Object)(object)InstanceFinder.ClientManager != (Object)null)
				{
					_clientRegistered = true;
					InstanceFinder.ClientManager.RegisterBroadcast<SwarmBarBroadcast>((Action<SwarmBarBroadcast, Channel>)OnSwarmBar);
				}
			}
		}

		private static void OnSwarmBar(SwarmBarBroadcast msg, Channel channel)
		{
			if (!InstanceFinder.IsServerStarted)
			{
				SwarmBar.Apply(msg);
			}
		}

		public static void SendSwarmBar(SwarmBarBroadcast msg)
		{
			if (!InstanceFinder.IsServerStarted || (Object)(object)InstanceFinder.ServerManager == (Object)null)
			{
				return;
			}
			try
			{
				InstanceFinder.ServerManager.Broadcast<SwarmBarBroadcast>(msg, true, (Channel)0);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to send the swarm bar update: " + ex));
			}
		}
	}
	public static class Patches
	{
		public static void ApplyAll(Harmony harmony)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Expected O, but got Unknown
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Expected O, but got Unknown
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Expected O, but got Unknown
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Expected O, but got Unknown
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Expected O, but got Unknown
			harmony.Patch((MethodBase)AccessTools.Method(typeof(ItemManager), "AvailableItemForBird", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "AvailableItemForBirdPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Bird), "SetCaughtFood", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "SetCaughtFoodPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(BirdManager), "AddFlyingBird", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "AddFlyingBirdPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(BirdManager), "RemoveFlyingBird", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "RemoveFlyingBirdPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(BirdManager), "SimulateBird", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "SimulateBirdPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(CreatureUtils), "GetFlyDirection", new Type[1] { typeof(Bird) }, (Type[])null), new HarmonyMethod(typeof(Patches), "GetFlyDirectionPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Weapon), "ShootEffects", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "ShootEffectsPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Boat), "FixedUpdate", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "BoatFixedUpdatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(BossManager), "InitializeBossFight", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "InitializeBossFightPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(BossManager), "OnPlayerCountChange", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "OnPlayerCountChangePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Creature), "ServerChangeHp", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "ServerChangeHpPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static bool AvailableItemForBirdPrefix(Bird bird, ref Item __result)
		{
			__result = Targeting.FindTarget(bird);
			return false;
		}

		private static void SetCaughtFoodPrefix(Bird __instance)
		{
			Targeting.PrepareForCatch(__instance);
		}

		private static void AddFlyingBirdPostfix(Bird bird)
		{
			Birds.Add(bird);
		}

		private static void RemoveFlyingBirdPostfix(Bird bird)
		{
			Birds.Remove(bird);
		}

		private static bool SimulateBirdPrefix(Bird bird)
		{
			if (BoatLift.IsCrew(bird))
			{
				BoatLift.SimulateCrewBird(bird);
				return false;
			}
			if (!Swarm.IsAttacking(bird))
			{
				return true;
			}
			Swarm.SimulateAttack(bird);
			return false;
		}

		private static bool GetFlyDirectionPrefix(Bird bird, ref Vector3 __result)
		{
			return HeldTargetFix.GetFlyDirection(bird, ref __result);
		}

		private static void ShootEffectsPostfix(Weapon __instance)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || (Object)(object)((Item)__instance).BirdHolder == (Object)null)
			{
				return;
			}
			Attachments attachments = __instance.Attachments;
			if (!((Object)(object)attachments == (Object)null) && !((Object)(object)attachments.FirePoint == (Object)null))
			{
				string fireSound = attachments.FireSound;
				if (!string.IsNullOrEmpty(fireSound))
				{
					AudioManager.PlayRandomClipAt(fireSound, 1, Mathf.Max(1, attachments.FireSoundCount), attachments.FirePoint.position, false, (AudioDistance)(attachments.UseMediumSoundDistance ? 2 : 3), attachments.FireSoundVolume, 0.1f);
				}
			}
		}

		private static void BoatFixedUpdatePostfix()
		{
			BoatLift.DriveBoat();
		}

		private static void InitializeBossFightPrefix()
		{
			SwarmBar.ForceHideForRealBoss();
		}

		private static bool OnPlayerCountChangePrefix()
		{
			return !SwarmBar.Showing;
		}

		private static void ServerChangeHpPostfix(Creature __instance)
		{
			Bird val = (Bird)(object)((__instance is Bird) ? __instance : null);
			if (val != null)
			{
				Swarm.OnBirdDamaged(val);
			}
		}
	}
	[BepInPlugin("dazed.howtofish.greedyseagulls", "GreedySeagulls", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "dazed.howtofish.greedyseagulls";

		public const string Name = "GreedySeagulls";

		public const string Version = "1.0.0";

		public static ManualLogSource Log;

		public static ConfigEntry<bool> StealFromHands;

		public static ConfigEntry<float> HandStealChance;

		public static ConfigEntry<bool> StealFromRods;

		public static ConfigEntry<float> RodStealChance;

		public static ConfigEntry<bool> StealTools;

		public static ConfigEntry<bool> StolenGunsFire;

		public static ConfigEntry<float> GunFireIntervalMin;

		public static ConfigEntry<float> GunFireIntervalMax;

		public static ConfigEntry<float> GunSpread;

		public static ConfigEntry<bool> SwarmEnabled;

		public static ConfigEntry<float> SwarmChance;

		public static ConfigEntry<float> SwarmCooldownMinutes;

		public static ConfigEntry<bool> StealHoldables;

		public static ConfigEntry<bool> RespectSeagullBlacklist;

		public static ConfigEntry<bool> RequireOpenSkyForHandSteal;

		public static ConfigEntry<int> SwarmExtraBirds;

		public static ConfigEntry<float> SwarmSpawnDistanceMin;

		public static ConfigEntry<float> SwarmSpawnDistanceMax;

		public static ConfigEntry<float> SwarmSpawnHeightJitter;

		public static ConfigEntry<float> SwarmApproachSpeed;

		public static ConfigEntry<float> SwarmDiveDelayMin;

		public static ConfigEntry<float> SwarmDiveDelayMax;

		public static ConfigEntry<float> SwarmCircleRadiusMin;

		public static ConfigEntry<float> SwarmCircleRadiusMax;

		public static ConfigEntry<float> SwarmDuration;

		public static ConfigEntry<int> SwarmDamage;

		public static ConfigEntry<float> SwarmHitRange;

		public static ConfigEntry<float> SwarmHitCooldown;

		public static ConfigEntry<float> SwarmKnockback;

		public static ConfigEntry<float> SwarmDiveSpeed;

		public static ConfigEntry<float> SwarmClimbSpeed;

		public static ConfigEntry<float> SwarmTurnSpeed;

		public static ConfigEntry<float> SwarmAcceleration;

		public static ConfigEntry<bool> SwarmRequireLineOfSight;

		public static ConfigEntry<float> SwarmBlockedRetry;

		public static ConfigEntry<bool> SwarmDespawnReinforcements;

		public static ConfigEntry<bool> SwarmAnnounceInChat;

		public static ConfigEntry<bool> SwarmBossBar;

		public static ConfigEntry<string> SwarmBossBarName;

		public static ConfigEntry<float> SwarmBarSendInterval;

		public static ConfigEntry<float> SwarmBarFailsafeGrace;

		public static ConfigEntry<bool> BoatLiftEnabled;

		public static ConfigEntry<int> BoatLiftRequiredBirds;

		public static ConfigEntry<int> BoatLiftMaxBirds;

		public static ConfigEntry<float> BoatLiftChance;

		public static ConfigEntry<float> BoatLiftCheckInterval;

		public static ConfigEntry<float> BoatLiftCooldownMinutes;

		public static ConfigEntry<float> BoatLiftGatherTimeout;

		public static ConfigEntry<float> BoatLiftDuration;

		public static ConfigEntry<float> BoatLiftRadiusX;

		public static ConfigEntry<float> BoatLiftRadiusZ;

		public static ConfigEntry<float> BoatLiftGripHeight;

		public static ConfigEntry<float> BoatLiftGripDistance;

		public static ConfigEntry<float> BoatLiftApproachSpeed;

		public static ConfigEntry<float> BoatLiftHoldSpeed;

		public static ConfigEntry<float> BoatLiftHeight;

		public static ConfigEntry<float> BoatLiftRiseSpeed;

		public static ConfigEntry<float> BoatLiftCruiseSpeed;

		public static ConfigEntry<float> BoatLiftLevelStrength;

		public static ConfigEntry<float> BoatLiftMaxLevelSpeed;

		public static ConfigEntry<float> BoatLiftOrbitRadiusMin;

		public static ConfigEntry<float> BoatLiftOrbitRadiusMax;

		public static ConfigEntry<float> BoatLiftOrbitCorrection;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			BindConfig();
			if (!Refl.Resolve())
			{
				Log.LogError((object)"Aborting: the game does not look the way this mod expects.");
				return;
			}
			Net.RegisterSerializers();
			_harmony = new Harmony("dazed.howtofish.greedyseagulls");
			Patches.ApplyAll(_harmony);
			Server.OnServerStopped += OnServerStopped;
			Log.LogInfo((object)"GreedySeagulls 1.0.0 loaded. Runs on the host only.");
		}

		private void BindConfig()
		{
			StealFromHands = ((BaseUnityPlugin)this).Config.Bind<bool>("Stealing", "StealFromHands", true, "Seagulls can snatch whatever a player is currently holding.");
			HandStealChance = ((BaseUnityPlugin)this).Config.Bind<float>("Stealing", "HandStealChance", 0.35f, "Chance from 0 to 1 that a held item is considered when a seagull picks a target. Seagulls only pick targets occasionally, so this is not a per second chance.");
			StealFromRods = ((BaseUnityPlugin)this).Config.Bind<bool>("Stealing", "StealFromRods", true, "Seagulls can snatch a fish hooked on a fishing rod once it is out of the water.");
			RodStealChance = ((BaseUnityPlugin)this).Config.Bind<float>("Stealing", "RodStealChance", 0.6f, "Chance from 0 to 1 that a hooked fish is considered when a seagull picks a target.");
			StealTools = ((BaseUnityPlugin)this).Config.Bind<bool>("Stealing", "StealTools", true, "Seagulls can steal tools and weapons, not just fish.");
			StealHoldables = ((BaseUnityPlugin)this).Config.Bind<bool>("Stealing", "StealHoldables", true, "Seagulls can steal anything else a player can pick up, such as radios.");
			RespectSeagullBlacklist = ((BaseUnityPlugin)this).Config.Bind<bool>("Stealing", "RespectSeagullBlacklist", true, "Honour the per item flag the developers use to keep seagulls away from certain objects. Turn this off if something you expect to be stealable never gets taken.");
			RequireOpenSkyForHandSteal = ((BaseUnityPlugin)this).Config.Bind<bool>("Stealing", "RequireOpenSkyForHandSteal", true, "A seagull will only dive for a held item if there is open sky above it. Turn this off if you want them to snatch things from under roofs and canopies.");
			StolenGunsFire = ((BaseUnityPlugin)this).Config.Bind<bool>("Stolen Guns", "StolenGunsFire", true, "A seagull carrying a gun fires it in whatever direction the barrel happens to be pointing.");
			GunFireIntervalMin = ((BaseUnityPlugin)this).Config.Bind<float>("Stolen Guns", "FireIntervalMin", 0.8f, "Shortest gap in seconds between shots from a stolen gun.");
			GunFireIntervalMax = ((BaseUnityPlugin)this).Config.Bind<float>("Stolen Guns", "FireIntervalMax", 3.5f, "Longest gap in seconds between shots from a stolen gun.");
			GunSpread = ((BaseUnityPlugin)this).Config.Bind<float>("Stolen Guns", "Spread", 0.12f, "Random cone added to the barrel direction. 0 fires exactly where the barrel points.");
			SwarmEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Swarm Event", "Enabled", true, "Attacking a seagull can enrage the whole flock.");
			SwarmChance = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "Chance", 0.1f, "Chance from 0 to 1 that damaging a seagull starts a swarm, once the cooldown has passed.");
			SwarmCooldownMinutes = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "CooldownMinutes", 30f, "Minutes that must pass after a swarm before another one can start.");
			SwarmExtraBirds = ((BaseUnityPlugin)this).Config.Bind<int>("Swarm Event", "ExtraBirds", 5, "How many extra seagulls join the swarm.");
			SwarmSpawnDistanceMin = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "SpawnDistanceMin", 90f, "Closest a reinforcement seagull can appear, measured from the provoked seagull. Kept large so they fly in from the horizon rather than popping in on top of you.");
			SwarmSpawnDistanceMax = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "SpawnDistanceMax", 150f, "Furthest a reinforcement seagull can appear.");
			SwarmSpawnHeightJitter = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "SpawnHeightJitter", 6f, "Random height variation applied at spawn so the flock is not a flat sheet.");
			SwarmApproachSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "ApproachSpeed", 14f, "Speed while flying in and circling before a dive.");
			SwarmDiveDelayMin = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "DiveDelayMin", 1f, "Shortest wait before a seagull commits to its next dive. Staggers the flock so they do not all swoop at once.");
			SwarmDiveDelayMax = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "DiveDelayMax", 9f, "Longest wait before a seagull commits to its next dive.");
			SwarmCircleRadiusMin = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "CircleRadiusMin", 8f, "Closest a circling seagull holds to its target while waiting to dive.");
			SwarmCircleRadiusMax = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "CircleRadiusMax", 22f, "Furthest a circling seagull holds to its target while waiting to dive. A wide spread means they attack from different angles.");
			SwarmDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "Duration", 75f, "How many seconds the swarm keeps attacking. Allow enough time for the reinforcements to fly in from their spawn distance.");
			SwarmDamage = ((BaseUnityPlugin)this).Config.Bind<int>("Swarm Event", "Damage", 4, "Damage per successful swoop.");
			SwarmHitRange = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "HitRange", 1.2f, "How close a seagull must get to land a swoop.");
			SwarmHitCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "HitCooldown", 1.5f, "Minimum seconds between hits from the same seagull.");
			SwarmKnockback = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "Knockback", 4f, "How hard a swoop shoves the player.");
			SwarmDiveSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "DiveSpeed", 20f, "Top speed while diving at a player.");
			SwarmClimbSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "ClimbSpeed", 15f, "Top speed while climbing back up between swoops.");
			SwarmTurnSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "TurnSpeed", 6f, "How sharply a swarming seagull can change direction.");
			SwarmAcceleration = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "Acceleration", 22f, "How fast a swarming seagull can change speed. Lower values make them ease into a dive instead of snapping to full speed.");
			SwarmRequireLineOfSight = ((BaseUnityPlugin)this).Config.Bind<bool>("Swarm Event", "RequireLineOfSight", true, "Seagulls will not start or continue a dive when level geometry is between them and their target, so they cannot hit you through walls or roofs.");
			SwarmBlockedRetry = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "BlockedRetry", 2f, "Seconds a seagull waits before looking for a new opening after its target ducks behind cover.");
			SwarmDespawnReinforcements = ((BaseUnityPlugin)this).Config.Bind<bool>("Swarm Event", "DespawnReinforcements", true, "Remove any surviving reinforcement seagulls when the swarm ends, so they do not build up over a long session.");
			SwarmAnnounceInChat = ((BaseUnityPlugin)this).Config.Bind<bool>("Swarm Event", "AnnounceInChat", true, "Post a chat line when a swarm starts.");
			SwarmBossBar = ((BaseUnityPlugin)this).Config.Bind<bool>("Swarm Event", "BossBar", true, "Show the swarm on the boss health bar. The bar is the combined health of every seagull taking part, so it drains as you shoot them down.");
			SwarmBossBarName = ((BaseUnityPlugin)this).Config.Bind<string>("Swarm Event", "BossBarName", "Seagull Swarm", "Label shown on the swarm boss bar.");
			SwarmBarSendInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "BarSendInterval", 0.2f, "How often at most the swarm bar is pushed to other players, in seconds.");
			SwarmBarFailsafeGrace = ((BaseUnityPlugin)this).Config.Bind<float>("Swarm Event", "BarFailsafeGrace", 20f, "Extra seconds past the swarm duration before a client clears the bar on its own. This exists so a lost host message can never leave the bar stuck, which would block respawning.");
			BoatLiftEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Boat Lift", "Enabled", true, "Seagulls can occasionally gang up and carry the boat away.");
			BoatLiftRequiredBirds = ((BaseUnityPlugin)this).Config.Bind<int>("Boat Lift", "RequiredBirds", 3, "How many free seagulls must be flying before they will try. The lift also aborts if the crew drops below this.");
			BoatLiftMaxBirds = ((BaseUnityPlugin)this).Config.Bind<int>("Boat Lift", "MaxBirds", 4, "Upper limit on how many seagulls take part.");
			BoatLiftChance = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "Chance", 0.05f, "Chance from 0 to 1 on each check that a lift starts.");
			BoatLiftCheckInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "CheckInterval", 45f, "Seconds between rolls for a lift.");
			BoatLiftCooldownMinutes = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "CooldownMinutes", 20f, "Minutes before another lift can start.");
			BoatLiftGatherTimeout = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "GatherTimeout", 25f, "Seconds the seagulls get to reach their grip points before giving up.");
			BoatLiftDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "Duration", 40f, "Seconds they carry the boat before dropping it.");
			BoatLiftRadiusX = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "RadiusX", 1.6f, "Half width of the ring of grip points, across the boat.");
			BoatLiftRadiusZ = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "RadiusZ", 3.2f, "Half length of the ring of grip points, along the boat. Larger than RadiusX so they sit along the hull sides.");
			BoatLiftGripHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "GripHeight", 0.9f, "Height of the grip points above the boat origin, roughly the top of the walls.");
			BoatLiftGripDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "GripDistance", 1.5f, "How close every seagull must be to its grip point before the lift begins.");
			BoatLiftApproachSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "ApproachSpeed", 16f, "Speed while flying to a grip point.");
			BoatLiftHoldSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "HoldSpeed", 12f, "How fast a seagull already on the boat corrects its position to stay on its grip point as the boat moves.");
			BoatLiftHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "Height", 10f, "How high above the water they carry the boat.");
			BoatLiftRiseSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "RiseSpeed", 1.5f, "How fast the boat climbs. Kept slow so it looks like a struggle.");
			BoatLiftCruiseSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Boat Lift", "CruiseSpeed", 2.5f, "How fast they haul the boat sideways once airborne.");
		}

		private void OnDestroy()
		{
			Server.OnServerStopped -= OnServerStopped;
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private static void OnServerStopped()
		{
			Swarm.Reset();
			BoatLift.Reset();
			SwarmBar.Apply(new SwarmBarBroadcast
			{
				Active = false
			});
			GunBird.Clear();
			Birds.Clear();
		}

		private void Update()
		{
			Net.TryRegisterHandlers();
			SwarmBar.LocalTick();
			if (InstanceFinder.IsServerStarted)
			{
				Birds.Prune();
				Swarm.Tick();
				BoatLift.Tick();
				GunBird.Tick(Birds.All);
			}
		}
	}
	public static class Refl
	{
		private static FieldInfo _weaponInfoField;

		private static MethodInfo _releaseItemFromBait;

		private static FieldInfo _bossField;

		private static FieldInfo _bossMaxHpField;

		private static FieldInfo _bossSpawnTickField;

		private static FieldInfo _bossLeavesTickField;

		private static FieldInfo _bossTotalTicksField;

		private static FieldInfo _playerUiInstance;

		private static FieldInfo _playerUiBossUi;

		private static FieldInfo _bossNameTextField;

		public static bool BossBarReady { get; private set; }

		public static bool Resolve()
		{
			bool flag = true;
			ResolveBossBar();
			_weaponInfoField = AccessTools.Field(typeof(Weapon), "_weaponInfo");
			flag &= Require(_weaponInfoField, "Weapon._weaponInfo");
			MethodInfo[] methods = typeof(Server).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name.StartsWith("RpcLogic___ReleaseItemFromBait___", StringComparison.Ordinal))
				{
					_releaseItemFromBait = methodInfo;
					break;
				}
			}
			return flag & Require(_releaseItemFromBait, "Server.RpcLogic___ReleaseItemFromBait___*");
		}

		private static bool Require(MemberInfo member, string name)
		{
			if (member != null)
			{
				return true;
			}
			Plugin.Log.LogError((object)("Could not find " + name + ". The game has probably updated."));
			return false;
		}

		private static void ResolveBossBar()
		{
			_bossField = AccessTools.Field(typeof(BossManager), "<Boss>k__BackingField");
			_bossMaxHpField = AccessTools.Field(typeof(BossManager), "<BossMaxHp>k__BackingField");
			_bossSpawnTickField = AccessTools.Field(typeof(BossManager), "<BossSpawnTick>k__BackingField");
			_bossLeavesTickField = AccessTools.Field(typeof(BossManager), "<BossLeavesTick>k__BackingField");
			_bossTotalTicksField = AccessTools.Field(typeof(BossManager), "<BossTotalTimeInTicks>k__BackingField");
			_playerUiInstance = AccessTools.Field(typeof(PlayerUI), "_instance");
			_playerUiBossUi = AccessTools.Field(typeof(PlayerUI), "_bossUI");
			_bossNameTextField = AccessTools.Field(typeof(BossUI), "_bossNameText");
			BossBarReady = _bossField != null && _bossMaxHpField != null && _bossSpawnTickField != null && _bossLeavesTickField != null && _bossTotalTicksField != null && _playerUiInstance != null && _playerUiBossUi != null && _bossNameTextField != null;
			if (!BossBarReady)
			{
				Plugin.Log.LogWarning((object)"Could not hook the boss bar. Everything else still works, the swarm just will not show a bar.");
			}
		}

		public static void SetFakeBoss(Creature creature, int maxHp, uint spawnTick, uint totalTicks)
		{
			if (BossBarReady)
			{
				_bossField.SetValue(null, creature);
				_bossMaxHpField.SetValue(null, maxHp);
				_bossSpawnTickField.SetValue(null, spawnTick);
				_bossTotalTicksField.SetValue(null, totalTicks);
				_bossLeavesTickField.SetValue(null, spawnTick + totalTicks);
			}
		}

		public static void ClearFakeBoss()
		{
			if (BossBarReady)
			{
				_bossField.SetValue(null, null);
				_bossMaxHpField.SetValue(null, 0);
				_bossSpawnTickField.SetValue(null, 0u);
				_bossLeavesTickField.SetValue(null, 0u);
				_bossTotalTicksField.SetValue(null, 0u);
			}
		}

		public static void SetBossBarName(string name)
		{
			if (!BossBarReady)
			{
				return;
			}
			object value = _playerUiInstance.GetValue(null);
			if (value == null)
			{
				return;
			}
			object value2 = _playerUiBossUi.GetValue(value);
			if (value2 != null)
			{
				object value3 = _bossNameTextField.GetValue(value2);
				if (value3 != null)
				{
					AccessTools.Property(value3.GetType(), "text")?.SetValue(value3, name, null);
				}
			}
		}

		public static WeaponInfo GetWeaponInfo(Weapon weapon)
		{
			if (_weaponInfoField == null || (Object)(object)weapon == (Object)null)
			{
				return null;
			}
			object? value = _weaponInfoField.GetValue(weapon);
			return (WeaponInfo)((value is WeaponInfo) ? value : null);
		}

		public static void ServerReleaseFromRod(FishingRod rod)
		{
			if (_releaseItemFromBait == null || (Object)(object)rod == (Object)null || (Object)(object)Server.Instance == (Object)null)
			{
				return;
			}
			try
			{
				_releaseItemFromBait.Invoke(Server.Instance, new object[1] { rod });
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not release item from rod: " + ex.Message));
			}
		}
	}
	public static class Swarm
	{
		private enum Phase
		{
			Approaching,
			Diving,
			Climbing
		}

		private class AttackState
		{
			public Player Target;

			public Phase Phase;

			public float NextDiveTime;

			public Vector3 ApproachOffset;

			public float NextDamage;
		}

		private static readonly Dictionary<Bird, AttackState> _attacking = new Dictionary<Bird, AttackState>();

		private static readonly List<NetworkObject> _spawned = new List<NetworkObject>();

		private static float _nextAllowedTime;

		private static float _endTime;

		private static int _barMax;

		public static bool Active => Time.time < _endTime;

		public static bool IsAttacking(Bird bird)
		{
			if ((Object)(object)bird != (Object)null)
			{
				return _attacking.ContainsKey(bird);
			}
			return false;
		}

		public static void Reset()
		{
			_attacking.Clear();
			_spawned.Clear();
			_nextAllowedTime = 0f;
			_endTime = 0f;
			_barMax = 0;
		}

		public static void ForceStart()
		{
			//IL_007d: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			Bird val = null;
			foreach (Bird item in Birds.All)
			{
				if ((Object)(object)item != (Object)null && !((Creature)item).IsDead)
				{
					val = item;
					break;
				}
			}
			if (BoatLift.Active)
			{
				Plugin.Log.LogWarning((object)"Cannot force a swarm while the seagulls are carrying the boat.");
				return;
			}
			if ((Object)(object)val == (Object)null)
			{
				Vector3 center = (((Object)(object)Player.LocalPlayer != (Object)null) ? Player.LocalPlayer.Transform.position : Vector3.zero);
				BirdSpawner.EnsureFreeBirds(1, center);
				foreach (Bird item2 in Birds.All)
				{
					if ((Object)(object)item2 != (Object)null && !((Creature)item2).IsDead)
					{
						val = item2;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Cannot force a swarm: no seagulls exist and none could be spawned.");
				return;
			}
			_nextAllowedTime = 0f;
			_endTime = 0f;
			Begin(val);
		}

		public static void OnBirdDamaged(Bird bird)
		{
			if (Plugin.SwarmEnabled.Value && !((Object)(object)bird == (Object)null) && !Active && !BoatLift.Active && !(Time.time < _nextAllowedTime) && !(Random.value > Plugin.SwarmChance.Value))
			{
				Begin(bird);
			}
		}

		private static void Begin(Bird source)
		{
			_nextAllowedTime = Time.time + Plugin.SwarmCooldownMinutes.Value * 60f;
			_endTime = Time.time + Plugin.SwarmDuration.Value;
			int num = SpawnReinforcements(source);
			foreach (Bird item in Birds.All)
			{
				if ((Object)(object)item != (Object)null && !((Creature)item).IsDead)
				{
					Enlist(item);
				}
			}
			_barMax = 0;
			RecalculateBar(out var current2, out var max);
			SwarmBar.Show(current2, max, DurationInTicks());
			Plugin.Log.LogInfo((object)$"Seagull swarm triggered. Spawned {num} reinforcement(s), {_attacking.Count} bird(s) attacking for {Plugin.SwarmDuration.Value}s.");
		}

		public static void Enlist(Bird bird)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)bird == (Object)null) && !_attacking.ContainsKey(bird) && !BoatLift.IsCrew(bird))
			{
				_attacking[bird] = new AttackState
				{
					Target = PickTarget(),
					Phase = Phase.Approaching,
					NextDiveTime = Time.time + RandomDiveDelay(),
					ApproachOffset = RandomApproachOffset(),
					NextDamage = 0f
				};
			}
		}

		private static float RandomDiveDelay()
		{
			float value = Plugin.SwarmDiveDelayMin.Value;
			float num = Mathf.Max(value, Plugin.SwarmDiveDelayMax.Value);
			return Random.Range(value, num);
		}

		private static Vector3 RandomApproachOffset()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			Vector2 insideUnitCircle = Random.insideUnitCircle;
			Vector2 val = ((Vector2)(ref insideUnitCircle)).normalized * Random.Range(Plugin.SwarmCircleRadiusMin.Value, Plugin.SwarmCircleRadiusMax.Value);
			return new Vector3(val.x, 0f, val.y);
		}

		private static int SpawnReinforcements(Bird template)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)template == (Object)null || Plugin.SwarmExtraBirds.Value <= 0)
			{
				return 0;
			}
			int num = BirdSpawner.SpawnRing(template, ((Component)template).transform.position, template.FlyHeigth, Plugin.SwarmExtraBirds.Value, Plugin.SwarmSpawnDistanceMin.Value, Plugin.SwarmSpawnDistanceMax.Value, Plugin.SwarmSpawnHeightJitter.Value, _spawned);
			if (num == 0)
			{
				Plugin.Log.LogWarning((object)"No reinforcement seagulls could be spawned. The swarm will use the birds already in the level.");
			}
			return num;
		}

		private static Player PickTarget()
		{
			List<Player> alivePlayers = PlayerManager.AlivePlayers;
			if (alivePlayers == null || alivePlayers.Count == 0)
			{
				return null;
			}
			return alivePlayers[Random.Range(0, alivePlayers.Count)];
		}

		public static void Tick()
		{
			if (Active)
			{
				if (PlayerManager.AlivePlayers == null || PlayerManager.AlivePlayers.Count == 0)
				{
					Plugin.Log.LogInfo((object)"Every player is down, ending the swarm early so they can respawn.");
					End();
					return;
				}
				foreach (Bird item in Birds.All)
				{
					if ((Object)(object)item != (Object)null && !((Creature)item).IsDead)
					{
						Enlist(item);
					}
				}
				RecalculateBar(out var current2, out var max);
				SwarmBar.UpdateHp(current2, max, DurationInTicks());
				if (current2 <= 0)
				{
					Plugin.Log.LogInfo((object)"Every swarming seagull is down.");
					End();
				}
			}
			else if (_attacking.Count > 0 || _spawned.Count > 0 || SwarmBar.Showing)
			{
				End();
			}
		}

		private static uint DurationInTicks()
		{
			int num = (((Object)(object)InstanceFinder.TimeManager != (Object)null) ? InstanceFinder.TimeManager.TickRate : 30);
			return (uint)Mathf.Max(1f, Plugin.SwarmDuration.Value * (float)num);
		}

		private static void RecalculateBar(out int current, out int max)
		{
			current = 0;
			int num = 0;
			foreach (KeyValuePair<Bird, AttackState> item in _attacking)
			{
				Bird key = item.Key;
				if (!((Object)(object)key == (Object)null))
				{
					num += Mathf.Max(1, ((Creature)key).MaxHp);
					if (!((Creature)key).IsDead)
					{
						current += Mathf.Max(0, ((Creature)key).Hp);
					}
				}
			}
			_barMax = Mathf.Max(_barMax, num);
			max = Mathf.Max(1, _barMax);
		}

		private static void End()
		{
			SwarmBar.Hide();
			_barMax = 0;
			_endTime = 0f;
			foreach (KeyValuePair<Bird, AttackState> item in _attacking)
			{
				if ((Object)(object)item.Key != (Object)null)
				{
					item.Key.SetSpeed(0f);
				}
			}
			_attacking.Clear();
			if (Plugin.SwarmDespawnReinforcements.Value)
			{
				foreach (NetworkObject item2 in _spawned)
				{
					if ((Object)(object)item2 != (Object)null && item2.IsSpawned)
					{
						InstanceFinder.ServerManager.Despawn(item2, (DespawnType?)null);
					}
				}
			}
			_spawned.Clear();
			Plugin.Log.LogInfo((object)"Seagull swarm over.");
		}

		public static void Forget(Bird bird)
		{
			if ((Object)(object)bird != (Object)null)
			{
				_attacking.Remove(bird);
			}
		}

		public static void SimulateAttack(Bird bird)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: 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_03a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Unknown result type (might be due to invalid IL or missing references)
			//IL_0419: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			if (!_attacking.TryGetValue(bird, out var value))
			{
				return;
			}
			if (((Creature)bird).IsDead)
			{
				_attacking.Remove(bird);
				return;
			}
			if ((Object)(object)bird.AttackingItem != (Object)null)
			{
				bird.SetAttackingFood((Item)null);
			}
			if (IsTargetGone(value.Target))
			{
				if (value.Phase == Phase.Diving)
				{
					value.Phase = Phase.Climbing;
				}
				value.Target = PickTarget();
				value.ApproachOffset = RandomApproachOffset();
				value.NextDiveTime = Time.time + RandomDiveDelay();
			}
			Vector3 position = ((Component)bird).transform.position;
			Vector3 val;
			float value2;
			byte animState;
			if ((Object)(object)value.Target == (Object)null)
			{
				Vector3 forward = ((Component)bird).transform.forward;
				forward.y = 0f;
				if (((Vector3)(ref forward)).sqrMagnitude < 0.01f)
				{
					forward = Vector3.forward;
				}
				((Vector3)(ref forward)).Normalize();
				bool num = position.y < bird.FlyHeigth - 1.5f;
				val = (num ? (forward + Vector3.up * 2f) : forward);
				value2 = Plugin.SwarmApproachSpeed.Value;
				animState = (byte)((!num) ? 1 : 4);
			}
			else
			{
				Vector3 val2 = value.Target.Transform.position + Vector3.up * 0.5f;
				switch (value.Phase)
				{
				case Phase.Climbing:
				{
					Vector3 val9 = position - val2;
					val9.y = 0f;
					if (((Vector3)(ref val9)).sqrMagnitude < 0.01f)
					{
						val9 = ((Component)bird).transform.forward;
						val9.y = 0f;
					}
					val = ((Vector3)(ref val9)).normalized + Vector3.up * 2f;
					value2 = Plugin.SwarmClimbSpeed.Value;
					animState = 4;
					if (position.y >= bird.FlyHeigth - 1.5f)
					{
						value.Phase = Phase.Approaching;
						value.Target = PickTarget();
						value.ApproachOffset = RandomApproachOffset();
						value.NextDiveTime = Time.time + RandomDiveDelay();
					}
					break;
				}
				case Phase.Diving:
				{
					Vector3 val7 = val2 - position;
					float magnitude = ((Vector3)(ref val7)).magnitude;
					val = ((Vector3)(ref val7)).normalized;
					value2 = Plugin.SwarmDiveSpeed.Value;
					animState = 2;
					if (!HasLineOfSight(position, val2))
					{
						value.Phase = Phase.Climbing;
					}
					else if (magnitude < Plugin.SwarmHitRange.Value)
					{
						if (Time.time >= value.NextDamage)
						{
							value.NextDamage = Time.time + Plugin.SwarmHitCooldown.Value;
							Vector3 val8 = val * Plugin.SwarmKnockback.Value;
							Server.Instance.HitPlayer(value.Target, Plugin.SwarmDamage.Value, val8, value.Target.Transform.position, (byte)1, (Player)null);
						}
						value.Phase = Phase.Climbing;
					}
					break;
				}
				default:
				{
					Vector3 val3 = val2 + value.ApproachOffset;
					val3.y = bird.FlyHeigth;
					Vector3 val4 = val3 - position;
					if (((Vector3)(ref val4)).sqrMagnitude < 4f)
					{
						Vector3 up = Vector3.up;
						Vector3 val5 = position - val2;
						Vector3 val6 = Vector3.Cross(up, ((Vector3)(ref val5)).normalized);
						val = ((((Vector3)(ref val6)).sqrMagnitude < 0.01f) ? ((Component)bird).transform.forward : val6);
					}
					else
					{
						val = ((Vector3)(ref val4)).normalized;
					}
					value2 = Plugin.SwarmApproachSpeed.Value;
					animState = 1;
					if (Time.time >= value.NextDiveTime)
					{
						if (HasLineOfSight(position, val2))
						{
							value.Phase = Phase.Diving;
							break;
						}
						value.NextDiveTime = Time.time + Plugin.SwarmBlockedRetry.Value;
						value.Target = PickTarget();
						value.ApproachOffset = RandomApproachOffset();
					}
					break;
				}
				}
			}
			((Vector3)(ref val)).Normalize();
			Vector3 val10 = Vector3.Lerp(((Component)bird).transform.forward, val, Time.deltaTime * Plugin.SwarmTurnSpeed.Value);
			if (((Vector3)(ref val10)).sqrMagnitude < 0.0001f)
			{
				val10 = val;
			}
			((Vector3)(ref val10)).Normalize();
			((Component)bird).transform.forward = val10;
			float num2 = Mathf.MoveTowards(bird.Speed, value2, Plugin.SwarmAcceleration.Value * Time.deltaTime);
			bird.SetSpeed(num2);
			Transform transform = ((Component)bird).transform;
			transform.position += val10 * (num2 * Time.deltaTime);
			bird.SetAnimState(animState);
		}

		private static bool IsTargetGone(Player target)
		{
			if (!((Object)(object)target == (Object)null) && !((Object)(object)target.Dying == (Object)null) && !target.Dying.IsDead && !((Object)(object)target.Vitals == (Object)null))
			{
				return target.Vitals.Health <= 0;
			}
			return true;
		}

		private static bool HasLineOfSight(Vector3 from, Vector3 to)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.SwarmRequireLineOfSight.Value)
			{
				return true;
			}
			Vector3 val = to - from;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 0.05f)
			{
				return true;
			}
			return !Physics.Raycast(from, val, magnitude - 0.15f, LayerMask.op_Implicit(GameInfo.LevelLayer));
		}
	}
	public static class SwarmBar
	{
		private static bool _showing;

		private static float _localExpiry;

		private static int _lastSentCurrent = -1;

		private static float _nextSend;

		public static bool Showing => _showing;

		public static void Show(int current, int max, uint totalTicks)
		{
			if (Plugin.SwarmBossBar.Value && Refl.BossBarReady)
			{
				uint spawnTick = (((Object)(object)InstanceFinder.TimeManager != (Object)null) ? InstanceFinder.TimeManager.Tick : 0u);
				SwarmBarBroadcast msg = new SwarmBarBroadcast
				{
					Active = true,
					Current = current,
					Max = max,
					SpawnTick = spawnTick,
					TotalTicks = totalTicks
				};
				Apply(msg);
				Net.SendSwarmBar(msg);
				_lastSentCurrent = current;
				_nextSend = Time.time + Plugin.SwarmBarSendInterval.Value;
			}
		}

		public static void UpdateHp(int current, int max, uint totalTicks)
		{
			if (_showing)
			{
				RefreshBossReference();
				PlayerUI.UpdateBossHp(current);
				if (current != _lastSentCurrent || !(Time.time < _nextSend))
				{
					_lastSentCurrent = current;
					_nextSend = Time.time + Plugin.SwarmBarSendInterval.Value;
					Net.SendSwarmBar(new SwarmBarBroadcast
					{
						Active = true,
						Current = current,
						Max = max,
						SpawnTick = (((Object)(object)InstanceFinder.TimeManager != (Object)null) ? InstanceFinder.TimeManager.Tick : 0u),
						TotalTicks = totalTicks
					});
				}
			}
		}

		public static void Hide()
		{
			if (_showing)
			{
				SwarmBarBroadcast msg = new SwarmBarBroadcast
				{
					Active = false
				};
				Apply(msg);
				Net.SendSwarmBar(msg);
				_lastSentCurrent = -1;
			}
		}

		public static void Apply(SwarmBarBroadcast msg)
		{
			if (!Refl.BossBarReady)
			{
				return;
			}
			if (!msg.Active)
			{
				if (_showing)
				{
					_showing = false;
					PlayerUI.ToggleBossUI(false);
					Refl.ClearFakeBoss();
				}
				return;
			}
			Creature val = FindLiveBird();
			if ((Object)(object)val == (Object)null || (!_showing && (Object)(object)BossManager.Boss != (Object)null))
			{
				return;
			}
			Refl.SetFakeBoss(val, Mathf.Max(1, msg.Max), msg.SpawnTick, msg.TotalTicks);
			int num = (((Object)(object)InstanceFinder.TimeManager != (Object)null) ? InstanceFinder.TimeManager.TickRate : 30);
			_localExpiry = Time.time + (float)(msg.TotalTicks / Mathf.Max(1, num)) + Plugin.SwarmBarFailsafeGrace.Value;
			if (!_showing)
			{
				_showing = true;
				PlayerUI.ToggleBossUI(true);
				if (Plugin.SwarmAnnounceInChat.Value)
				{
					ChatManager.ChatMessage("<i>The seagulls have had enough.</i>");
				}
			}
			Refl.SetBossBarName(Plugin.SwarmBossBarName.Value);
			PlayerUI.UpdateBossHp(msg.Current);
		}

		public static void LocalTick()
		{
			if (_showing && !(Time.time < _localExpiry))
			{
				Plugin.Log.LogWarning((object)"The swarm bar outlived its timer without a message from the host, clearing it so respawning is not blocked.");
				_showing = false;
				PlayerUI.ToggleBossUI(false);
				Refl.ClearFakeBoss();
				_lastSentCurrent = -1;
			}
		}

		public static void ForceHideForRealBoss()
		{
			if (_showing)
			{
				_showing = false;
				PlayerUI.ToggleBossUI(false);
				Refl.ClearFakeBoss();
				_lastSentCurrent = -1;
				Plugin.Log.LogInfo((object)"A real boss spawned, so the swarm bar stepped aside.");
			}
		}

		private static void RefreshBossReference()
		{
			if (_showing && !((Object)(object)BossManager.Boss != (Object)null))
			{
				Creature val = FindLiveBird();
				if ((Object)(object)val != (Object)null)
				{
					Refl.SetFakeBoss(val, Mathf.Max(1, BossManager.BossMaxHp), BossManager.BossSpawnTick, BossManager.BossTotalTimeInTicks);
				}
			}
		}

		private static Creature FindLiveBird()
		{
			foreach (Bird item in Birds.All)
			{
				if ((Object)(object)item != (Object)null && !((Creature)item).IsDead)
				{
					return (Creature)(object)item;
				}
			}
			foreach (Bird item2 in Birds.All)
			{
				if ((Object)(object)item2 != (Object)null)
				{
					return (Creature)(object)item2;
				}
			}
			return null;
		}
	}
	public static class Targeting
	{
		public enum Kind
		{
			None,
			Fish,
			Corpse,
			Tool,
			Holdable
		}

		private static readonly HashSet<Item> _seen = new HashSet<Item>();

		public static Item FindTarget(Bird bird)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)bird == (Object)null)
			{
				return null;
			}
			_seen.Clear();
			Item result = null;
			float num = float.MaxValue;
			Vector3 position = ((Component)bird).transform.position;
			foreach (KeyValuePair<Transform, Item> item in ItemManager.Items)
			{
				Item value = item.Value;
				if (!((Object)(object)value == (Object)null) && _seen.Add(value) && IsEligible(value))
				{
					Vector3 val = ((Component)value).transform.position - position;
					float magnitude = ((Vector3)(ref val)).magnitude;
					if (!(magnitude >= num) && !Physics.Raycast(position, val, Mathf.Clamp(magnitude - 0.15f, 0f, magnitude), LayerMask.op_Implicit(GameInfo.LevelLayer)))
					{
						num = magnitude;
						result = value;
					}
				}
			}
			return result;
		}

		public static Kind Categorize(Item item)
		{
			Creature creature = item.Creature;
			if ((Object)(object)creature != (Object)null)
			{
				if (!creature.IsDead)
				{
					return Kind.None;
				}
				return Kind.Fish;
			}
			if ((Object)(object)item.DeadPlayer != (Object)null)
			{
				return Kind.Corpse;
			}
			if ((Object)(object)item.Tool != (Object)null)
			{
				return Kind.Tool;
			}
			if (!item.CanPickUp)
			{
				return Kind.None;
			}
			return Kind.Holdable;
		}

		private static bool KindAllowed(Kind kind)
		{
			switch (kind)
			{
			case Kind.Tool:
				return Plugin.StealTools.Value;
			case Kind.Holdable:
				return Plugin.StealHoldables.Value;
			case Kind.Fish:
			case Kind.Corpse:
				return true;
			default:
				return false;
			}
		}

		private static bool IsEligible(Item item)
		{
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)item).IsDeinitializing || item.IsDestroying)
			{
				return false;
			}
			if ((Object)(object)item.BirdHolder != (Object)null || (Object)(object)item.Bird != (Object)null)
			{
				return false;
			}
			if (!item.IsInteractable)
			{
				return false;
			}
			bool flag = (Object)(object)item.AttachedRod != (Object)null;
			Creature creature = item.Creature;
			bool flag2 = (Object)(object)creature != (Object)null && !creature.IsDead;
			if (item.IgnoredBySeagulls && Plugin.RespectSeagullBlacklist.Value)
			{
				return false;
			}
			if (!KindAllowed((flag2 && flag) ? Kind.Fish : Categorize(item)))
			{
				return false;
			}
			if ((Object)(object)item.SyncedHolder != (Object)null || (Object)(object)item.Holder != (Object)null)
			{
				if (!Plugin.StealFromHands.Value)
				{
					return false;
				}
				return Random.value <= Plugin.HandStealChance.Value;
			}
			if (flag)
			{
				if (!Plugin.StealFromRods.Value)
				{
					return false;
				}
				if (((Component)item).transform.position.y <= WaterManager.WaterHeight)
				{
					return false;
				}
				return Random.value <= Plugin.RodStealChance.Value;
			}
			return !flag2;
		}

		public static void PrepareForCatch(Bird bird)
		{
			//IL_005e: 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_0067: 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)
			Item val = (((Object)(object)bird != (Object)null) ? bird.AttackingItem : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			FishingRod attachedRod = val.AttachedRod;
			if ((Object)(object)attachedRod != (Object)null)
			{
				Refl.ServerReleaseFromRod(attachedRod);
			}
			Player val2 = (((Object)(object)val.SyncedHolder != (Object)null) ? val.SyncedHolder : val.Holder);
			if (!((Object)(object)val2 == (Object)null))
			{
				val.Drop(false, default(Vector3), default(Vector3));
				val.SetSyncedHolder((Player)null, true);
				if ((Object)(object)val.Holder != (Object)null)
				{
					Plugin.Log.LogWarning((object)("'" + val.GetName() + "' would not let go of " + val2.SteamName + "; the seagull will lose it."));
				}
				else
				{
					Plugin.Log.LogInfo((object)("A seagull snatched '" + val.GetName() + "' out of " + val2.SteamName + "'s hands."));
				}
			}
		}
	}
}