Decompiled source of TameAI v1.1.6

BepInEx/plugins/Goblinheim - TameAI/NicoMods.TameAI.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("NicoMods.TameAI")]
[assembly: AssemblyDescription("Lightweight local navigation safeguards for tamed Valheim creatures")]
[assembly: AssemblyCompany("NicoMods")]
[assembly: AssemblyProduct("NicoMods.TameAI")]
[assembly: AssemblyCopyright("Copyright © 2026 NicoMods")]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("1.1.6.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.1.6.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 NicoMods.TameAI
{
	internal static class Authority
	{
		private const string CompanionAlpha = "GoblinHeim.Companion.Alpha";

		private const string CompanionWounded = "GoblinHeim.Companion.Wounded";

		private const string CompanionHealing = "GoblinHeim.Companion.Healing";

		private const string CompanionRecovery = "GoblinHeim.Companion.RecoveryPending";

		internal static bool IsCompanionAlpha(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			ZNetView component = ((Component)character).GetComponent<ZNetView>();
			ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
			if (val != null)
			{
				return val.GetBool("GoblinHeim.Companion.Alpha", false);
			}
			return false;
		}

		internal static bool IsLocalParkedTame(BaseAI ai, out Character character, out MonsterAI monster)
		{
			if (!IsLocalTame(ai, out character, out monster))
			{
				return false;
			}
			if ((Object)(object)monster.GetFollowTarget() != (Object)null)
			{
				return false;
			}
			return true;
		}

		internal static bool IsLocalFollowingTame(BaseAI ai, GameObject expectedTarget, out Character character, out MonsterAI monster)
		{
			if (!IsLocalTame(ai, out character, out monster))
			{
				return false;
			}
			if ((Object)(object)expectedTarget != (Object)null)
			{
				return (Object)(object)monster.GetFollowTarget() == (Object)(object)expectedTarget;
			}
			return false;
		}

		private static bool IsLocalTame(BaseAI ai, out Character character, out MonsterAI monster)
		{
			character = null;
			monster = (MonsterAI)(object)((ai is MonsterAI) ? ai : null);
			if (!TameAIPlugin.Enabled.Value || (Object)(object)ai == (Object)null || (Object)(object)monster == (Object)null)
			{
				return false;
			}
			character = ((Component)ai).GetComponent<Character>();
			ZNetView component = ((Component)ai).GetComponent<ZNetView>();
			if ((Object)(object)character == (Object)null || (Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner() || character.IsDead() || !character.IsTamed())
			{
				return false;
			}
			if (character.HaveRider() || character.IsAttached())
			{
				return false;
			}
			ZDO zDO = component.GetZDO();
			if (zDO != null && zDO.GetBool("GoblinHeim.Companion.Alpha", false) && (zDO.GetBool("GoblinHeim.Companion.Wounded", false) || zDO.GetBool("GoblinHeim.Companion.Healing", false) || zDO.GetBool("GoblinHeim.Companion.RecoveryPending", false)))
			{
				return false;
			}
			return true;
		}
	}
	internal enum RefusalReason
	{
		None,
		Water,
		Lava,
		Fire,
		Smoke,
		Trap,
		Structure,
		NarrowOpening,
		Occupied,
		NoPath
	}
	internal static class HazardScanner
	{
		private static readonly Collider[] Hits = (Collider[])(object)new Collider[48];

		private static readonly RaycastHit[] CastHits = (RaycastHit[])(object)new RaycastHit[24];

		private static int solidMask = -1;

		private static int smokeMask = -1;

		private static int SolidMask
		{
			get
			{
				if (solidMask < 0)
				{
					solidMask = LayerMask.GetMask(new string[5] { "Default", "Default_small", "static_solid", "piece", "vehicle" });
				}
				return solidMask;
			}
		}

		private static int SmokeMask
		{
			get
			{
				if (smokeMask < 0)
				{
					smokeMask = LayerMask.GetMask(new string[1] { "smoke" });
				}
				return smokeMask;
			}
		}

		internal static RefusalReason Judge(BaseAI ai, Character character, Vector3 point, bool allowOccupied = false)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_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_008b: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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_010a: 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)
			if (TameAIPlugin.AvoidLava.Value && (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.IsLava(point, false))
			{
				return RefusalReason.Lava;
			}
			if (TameAIPlugin.AvoidFire.Value && Object.op_Implicit((Object)(object)EffectArea.IsPointInsideArea(point, (Type)2, 0f)))
			{
				return RefusalReason.Fire;
			}
			if (TameAIPlugin.AvoidSmoke.Value && Physics.CheckSphere(point + Vector3.up * 0.5f, 0.5f, SmokeMask, (QueryTriggerInteraction)2))
			{
				return RefusalReason.Smoke;
			}
			if (TameAIPlugin.AvoidTraps.Value && HarmfulAoe(point, 1.5f))
			{
				return RefusalReason.Trap;
			}
			BodySize(character, out var radius, out var height);
			if (TameAIPlugin.AvoidSwimming.Value && IsWaterDestination(character, point, height))
			{
				return RefusalReason.Water;
			}
			if (TameAIPlugin.StructureAwareness.Value)
			{
				if (BlockedAt(character, point, radius, height))
				{
					return RefusalReason.Structure;
				}
				if (BlockedBetween(character, ((Component)character).transform.position, point, radius, height))
				{
					return RefusalReason.NarrowOpening;
				}
				if ((Object)(object)Pathfinding.instance != (Object)null && !Pathfinding.instance.HavePath(((Component)ai).transform.position, point, ai.m_pathAgentType))
				{
					return RefusalReason.NoPath;
				}
			}
			if (!allowOccupied && TameAIPlugin.AnimalSeparation.Value && Occupied(character, point, radius))
			{
				return RefusalReason.Occupied;
			}
			return RefusalReason.None;
		}

		internal static RefusalReason JudgeRestingArea(Character character, Vector3 point)
		{
			//IL_0018: 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)
			if ((Object)(object)character == (Object)null)
			{
				return RefusalReason.None;
			}
			if (TameAIPlugin.StructureAwareness.Value && !ClearOfBuiltPieces(character, point, TameAIPlugin.RestingClearance.Value))
			{
				return RefusalReason.Structure;
			}
			if (TameAIPlugin.AnimalSeparation.Value && !ClearOfOtherTames(character, point))
			{
				return RefusalReason.Occupied;
			}
			return RefusalReason.None;
		}

		internal static bool NearbyConstructedHazard(Character character, float searchRadius, out Vector3 origin, out float keepAway, out string name)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: 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)
			origin = Vector3.zero;
			keepAway = 0f;
			name = null;
			int num = Physics.OverlapSphereNonAlloc(((Component)character).transform.position, searchRadius, Hits, -1, (QueryTriggerInteraction)2);
			float num2 = float.MaxValue;
			for (int i = 0; i < num; i++)
			{
				Collider val = Hits[i];
				if ((Object)(object)val == (Object)null || ((Component)val).transform.IsChildOf(((Component)character).transform))
				{
					continue;
				}
				Aoe componentInParent = ((Component)val).GetComponentInParent<Aoe>();
				if ((Object)(object)componentInParent == (Object)null || !componentInParent.m_hitCharacters || !componentInParent.m_hitFriendly || ((DamageTypes)(ref componentInParent.m_damage)).GetTotalDamage() <= 0f)
				{
					continue;
				}
				Piece componentInParent2 = ((Component)componentInParent).GetComponentInParent<Piece>();
				if (!((Object)(object)componentInParent2 == (Object)null))
				{
					Vector3 val2 = val.ClosestPoint(((Component)character).transform.position);
					float num3 = Vector3.Distance(((Component)character).transform.position, val2);
					float num4 = Mathf.Max(1.5f, componentInParent.m_radius + 1.25f);
					if (!(num3 > num4) && !(num3 >= num2))
					{
						num2 = num3;
						origin = ((Component)componentInParent).transform.position;
						keepAway = num4;
						name = Utils.GetPrefabName(((Component)componentInParent2).gameObject);
					}
				}
			}
			return num2 < float.MaxValue;
		}

		internal static void ArmVanilla(BaseAI ai)
		{
			if (TameAIPlugin.AvoidFire.Value)
			{
				ai.m_avoidFire = true;
			}
			if (TameAIPlugin.AvoidLava.Value)
			{
				ai.m_avoidLava = true;
			}
			if (TameAIPlugin.AvoidSwimming.Value)
			{
				ai.m_avoidWater = true;
			}
		}

		internal static bool DangerAt(Character character, Vector3 point, bool allowWater = false)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			if (TameAIPlugin.AvoidLava.Value && (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.IsLava(point, false))
			{
				return true;
			}
			if (TameAIPlugin.AvoidFire.Value && Object.op_Implicit((Object)(object)EffectArea.IsPointInsideArea(point, (Type)2, 0f)))
			{
				return true;
			}
			if (TameAIPlugin.AvoidSmoke.Value && Physics.CheckSphere(point + Vector3.up * 0.5f, 0.5f, SmokeMask, (QueryTriggerInteraction)2))
			{
				return true;
			}
			if (TameAIPlugin.AvoidTraps.Value && HarmfulAoe(point, 1.25f))
			{
				return true;
			}
			BodySize(character, out var _, out var height);
			if (!allowWater && TameAIPlugin.AvoidSwimming.Value)
			{
				return IsWaterDestination(character, point, height);
			}
			return false;
		}

		internal static bool SafeFollowSegment(Character character, Vector3 from, Vector3 to, bool allowWater = false)
		{
			//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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			//IL_0055: 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)
			int num = Mathf.Clamp(Mathf.CeilToInt(Vector3.Distance(from, to) / 2f), 1, 8);
			float y = default(float);
			for (int i = 1; i <= num; i++)
			{
				Vector3 val = Vector3.Lerp(from, to, (float)i / (float)num);
				if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetSolidHeight(val, ref y, 1000))
				{
					val.y = y;
				}
				if (DangerAt(character, val, allowWater))
				{
					return false;
				}
			}
			return true;
		}

		private static bool IsWaterDestination(Character character, Vector3 point, float height)
		{
			//IL_001c: 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)
			if (character.IsFlying() || (Object)(object)ZoneSystem.instance == (Object)null)
			{
				return false;
			}
			float num = default(float);
			if (!ZoneSystem.instance.GetSolidHeight(point, ref num, 1000))
			{
				return true;
			}
			float waterLevel = ZoneSystem.instance.m_waterLevel;
			float num2 = Mathf.Max(0.25f, height * 0.22f);
			if (!character.IsSwimming())
			{
				return num < waterLevel - num2;
			}
			float num3 = default(float);
			if (ZoneSystem.instance.GetSolidHeight(((Component)character).transform.position, ref num3, 1000))
			{
				return num < num3 - 0.15f;
			}
			return false;
		}

		private static bool HarmfulAoe(Vector3 point, float margin)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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)
			int num = Physics.OverlapSphereNonAlloc(point, margin, Hits, -1, (QueryTriggerInteraction)2);
			for (int i = 0; i < num; i++)
			{
				Collider val = Hits[i];
				if (!((Object)(object)val == (Object)null))
				{
					Aoe componentInParent = ((Component)val).GetComponentInParent<Aoe>();
					if ((Object)(object)componentInParent != (Object)null && componentInParent.m_hitCharacters && componentInParent.m_hitFriendly && ((DamageTypes)(ref componentInParent.m_damage)).GetTotalDamage() > 0f && Vector3.Distance(point, ((Component)componentInParent).transform.position) <= componentInParent.m_radius + margin)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool BlockedAt(Character self, Vector3 point, float radius, float height)
		{
			//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: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//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_002a: 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_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_005d: 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)
			Vector3 val = point + Vector3.up * radius;
			Vector3 val2 = point + Vector3.up * Mathf.Max(radius, height - radius);
			int num = Physics.OverlapCapsuleNonAlloc(val, val2, radius, Hits, SolidMask, (QueryTriggerInteraction)1);
			for (int i = 0; i < num; i++)
			{
				Collider val3 = Hits[i];
				if (Foreign(self, val3))
				{
					Bounds bounds = val3.bounds;
					if (((Bounds)(ref bounds)).max.y > point.y + 0.15f)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool BlockedBetween(Character self, Vector3 from, Vector3 to, float radius, float height)
		{
			//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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_004b: 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_0060: 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)
			Vector3 val = from + Vector3.up * Mathf.Clamp(height * 0.45f, radius, height - radius);
			Vector3 val2 = to + Vector3.up * Mathf.Clamp(height * 0.45f, radius, height - radius) - val;
			float magnitude = ((Vector3)(ref val2)).magnitude;
			if (magnitude < 0.1f)
			{
				return false;
			}
			int num = Physics.SphereCastNonAlloc(val, radius, val2 / magnitude, CastHits, magnitude, SolidMask, (QueryTriggerInteraction)1);
			for (int i = 0; i < num; i++)
			{
				if (Foreign(self, ((RaycastHit)(ref CastHits[i])).collider))
				{
					return true;
				}
			}
			return false;
		}

		private static bool Occupied(Character self, Vector3 point, float radius)
		{
			//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: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.OverlapSphereNonAlloc(point + Vector3.up * radius, radius * 1.35f + TameAIPlugin.SeparationMargin.Value, Hits, -1, (QueryTriggerInteraction)1);
			for (int i = 0; i < num; i++)
			{
				Collider val = Hits[i];
				if (!((Object)(object)val == (Object)null) && !((Component)val).transform.IsChildOf(((Component)self).transform))
				{
					Character componentInParent = ((Component)val).GetComponentInParent<Character>();
					if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent != (Object)(object)self && !componentInParent.IsDead())
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool ClearOfBuiltPieces(Character self, Vector3 point, float clearance)
		{
			//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_000b: 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_0016: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_008b: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = point + Vector3.up * 0.75f;
			int num = Physics.OverlapSphereNonAlloc(val, clearance, Hits, SolidMask, (QueryTriggerInteraction)1);
			for (int i = 0; i < num; i++)
			{
				Collider val2 = Hits[i];
				if ((Object)(object)val2 == (Object)null || ((Component)val2).transform.IsChildOf(((Component)self).transform) || (Object)(object)((Component)val2).GetComponentInParent<Piece>() == (Object)null)
				{
					continue;
				}
				Bounds bounds = val2.bounds;
				if (!(((Bounds)(ref bounds)).max.y <= point.y + 0.25f))
				{
					Vector3 val3 = val2.ClosestPoint(val);
					val3.y = val.y;
					Vector3 val4 = val3 - val;
					val4.y = 0f;
					if (((Vector3)(ref val4)).sqrMagnitude < clearance * clearance)
					{
						return false;
					}
				}
			}
			return true;
		}

		private static bool ClearOfOtherTames(Character self, Vector3 point)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(0.25f, self.GetRadius());
			List<Character> allCharacters = Character.GetAllCharacters();
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)self) && !val.IsDead() && val.IsTamed())
				{
					Vector3 val2 = ((Component)val).transform.position - point;
					val2.y = 0f;
					float num2 = num + Mathf.Max(0.25f, val.GetRadius()) + TameAIPlugin.SeparationMargin.Value;
					if (((Vector3)(ref val2)).sqrMagnitude < num2 * num2)
					{
						return false;
					}
				}
			}
			return true;
		}

		private static bool Foreign(Character self, Collider hit)
		{
			if ((Object)(object)hit == (Object)null || hit.isTrigger || ((Component)hit).transform.IsChildOf(((Component)self).transform))
			{
				return false;
			}
			return (Object)(object)((Component)hit).GetComponentInParent<Character>() == (Object)null;
		}

		private static void BodySize(Character character, out float radius, out float height)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			CapsuleCollider component = ((Component)character).GetComponent<CapsuleCollider>();
			if ((Object)(object)component != (Object)null)
			{
				Vector3 lossyScale = ((Component)component).transform.lossyScale;
				radius = component.radius * Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.z));
				height = component.height * Mathf.Abs(lossyScale.y);
			}
			else
			{
				Collider component2 = ((Component)character).GetComponent<Collider>();
				if ((Object)(object)component2 != (Object)null)
				{
					Bounds bounds = component2.bounds;
					radius = Mathf.Max(((Bounds)(ref bounds)).extents.x, ((Bounds)(ref bounds)).extents.z);
					height = ((Bounds)(ref bounds)).size.y;
				}
				else
				{
					radius = 0.45f;
					height = 1.5f;
				}
			}
			radius = Mathf.Clamp(radius + TameAIPlugin.StructureMargin.Value, 0.3f, 2.5f);
			height = Mathf.Max(height, radius * 2f + 0.05f);
		}
	}
	internal static class LocalBehaviour
	{
		private enum Mode
		{
			None,
			HazardEscape,
			SocialApproach,
			SocialPause,
			PlayerApproach
		}

		private sealed class State
		{
			internal Mode Current;

			internal Vector3 Target;

			internal Vector3 HarmDirection;

			internal float Until;

			internal float NextHazardScan;

			internal float NextSocial;

			internal float NextPlayerScan;

			internal float NextPathCheck;

			internal int SocialPartner;

			internal int DetectedPlayer;

			internal string HazardName;
		}

		private static readonly Dictionary<int, State> States = new Dictionary<int, State>();

		private static readonly Func<BaseAI, float, Vector3, float, bool, bool> MoveTo = AccessTools.MethodDelegate<Func<BaseAI, float, Vector3, float, bool, bool>>(AccessTools.Method(typeof(BaseAI), "MoveTo", new Type[4]
		{
			typeof(float),
			typeof(Vector3),
			typeof(float),
			typeof(bool)
		}, (Type[])null), (object)null, true);

		internal static void Clear()
		{
			States.Clear();
		}

		internal static void Forget(BaseAI ai)
		{
			if ((Object)(object)ai != (Object)null)
			{
				States.Remove(((Object)ai).GetInstanceID());
			}
		}

		internal static bool HasNearbyPlayer(Vector3 point)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZoneSystem.instance == (Object)null)
			{
				return false;
			}
			float num = Mathf.Max(80f, ZoneSystem.instance.m_zoneSize * 1.5f);
			return (Object)(object)Player.GetClosestPlayer(point, num) != (Object)null;
		}

		internal static void EnvironmentalDamage(Character character, HitData hit)
		{
			//IL_002b: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00f2: 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_0127: 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_00e7: 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_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_00c0: Unknown result type (might be due to invalid IL or missing references)
			if (!TameAIPlugin.CalmHazardEscape.Value || (Object)(object)character == (Object)null || hit == null || !((DamageTypes)(ref hit.m_damage)).HaveDamage() || !HasNearbyPlayer(((Component)character).transform.position))
			{
				return;
			}
			BaseAI baseAI = character.GetBaseAI();
			if (!Authority.IsLocalParkedTame(baseAI, out var character2, out var _) || Authority.IsCompanionAlpha(character2))
			{
				return;
			}
			Character attacker = hit.GetAttacker();
			if (!((Object)(object)attacker != (Object)null) || attacker is Player)
			{
				State state = Get(baseAI);
				Vector3 val = hit.m_dir;
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude < 0.01f && hit.m_point != Vector3.zero)
				{
					val = ((Component)character).transform.position - hit.m_point;
					val.y = 0f;
				}
				if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
				{
					val = ((Component)character).transform.forward;
				}
				state.HarmDirection = ((Vector3)(ref val)).normalized;
				state.Current = Mode.HazardEscape;
				state.Until = Time.time + 1.5f;
				PickEscape(baseAI, character, state, ((Component)character).transform.position - state.HarmDirection, 4f);
			}
		}

		internal static bool BeforeIdle(BaseAI ai, float dt)
		{
			//IL_002a: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: 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_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0372: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: 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_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: 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_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			if (!Authority.IsLocalParkedTame(ai, out var character, out var _))
			{
				Forget(ai);
				return true;
			}
			if (Authority.IsCompanionAlpha(character))
			{
				Forget(ai);
				return true;
			}
			if (!HasNearbyPlayer(((Component)character).transform.position))
			{
				Forget(ai);
				return true;
			}
			State state = Get(ai);
			float time = Time.time;
			if (state.NextHazardScan <= time)
			{
				state.NextHazardScan = time + 0.75f + StableFraction(((Object)ai).GetInstanceID(), 0.55f);
				if (TameAIPlugin.CalmHazardEscape.Value && HazardScanner.NearbyConstructedHazard(character, 8f, out var origin, out var keepAway, out var name))
				{
					Vector3 val = ((Component)character).transform.position - origin;
					val.y = 0f;
					if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
					{
						val = ((Component)character).transform.forward;
					}
					state.HarmDirection = ((Vector3)(ref val)).normalized;
					state.Current = Mode.HazardEscape;
					state.Until = time + 1.5f;
					state.HazardName = name;
					PickEscape(ai, character, state, origin, Mathf.Clamp(keepAway + 1f, 3f, 7f));
				}
			}
			if (state.Current == Mode.HazardEscape)
			{
				if (time > state.Until)
				{
					state.Current = Mode.None;
					ai.ResetRandomMovement();
					return false;
				}
				if (!SafeTarget(ai, character, state.Target))
				{
					PickEscape(ai, character, state, ((Component)character).transform.position - state.HarmDirection, 4f);
				}
				if (MoveTo(ai, dt, state.Target, 0.6f, arg5: false))
				{
					state.Current = Mode.None;
					ai.ResetRandomMovement();
				}
				return false;
			}
			if (state.Current == Mode.PlayerApproach)
			{
				if (time > state.Until || (time >= state.NextPathCheck && !SafeTarget(ai, character, state.Target, allowOccupied: true)))
				{
					state.Current = Mode.None;
					ai.ResetRandomMovement();
					return false;
				}
				if (time >= state.NextPathCheck)
				{
					state.NextPathCheck = time + 1f;
				}
				if (MoveTo(ai, dt, state.Target, 1f, arg5: false))
				{
					state.Current = Mode.None;
					ai.ResetRandomMovement();
				}
				return false;
			}
			if (state.Current == Mode.SocialApproach)
			{
				Character val2 = FindByInstance(state.SocialPartner);
				if ((Object)(object)val2 == (Object)null || val2.IsDead() || time > state.Until)
				{
					EndSocial(ai, state, time);
					return false;
				}
				Vector3 val3 = ((Component)val2).transform.position - ((Component)character).transform.position;
				val3.y = 0f;
				if (((Vector3)(ref val3)).sqrMagnitude <= 5.75f)
				{
					state.Current = Mode.SocialPause;
					state.Until = time + 2f + StableFraction(((Object)ai).GetInstanceID(), 2.5f);
					character.SetLookDir(((Vector3)(ref val3)).normalized, 0f);
					return false;
				}
				Vector3 target = ((Component)val2).transform.position - ((Vector3)(ref val3)).normalized * Mathf.Max(1.2f, character.GetRadius() + val2.GetRadius() + 0.35f);
				if (!SafeTarget(ai, character, target, allowOccupied: true))
				{
					EndSocial(ai, state, time);
					return false;
				}
				state.Target = target;
				MoveTo(ai, dt, state.Target, 1f, arg5: false);
				return false;
			}
			if (state.Current == Mode.SocialPause)
			{
				Character val4 = FindByInstance(state.SocialPartner);
				if ((Object)(object)val4 != (Object)null)
				{
					Vector3 val5 = ((Component)val4).transform.position - ((Component)character).transform.position;
					val5.y = 0f;
					if (((Vector3)(ref val5)).sqrMagnitude > 0.01f)
					{
						character.SetLookDir(((Vector3)(ref val5)).normalized, 0f);
					}
				}
				if (time >= state.Until)
				{
					EndSocial(ai, state, time);
				}
				return false;
			}
			if (TameAIPlugin.PlayerCuriosity.Value && time >= state.NextPlayerScan)
			{
				state.NextPlayerScan = time + 4f + StableFraction(((Object)ai).GetInstanceID() + Mathf.FloorToInt(time / 4f), 3f);
				TryPlayerCuriosity(ai, character, state, time);
				if (state.Current != Mode.None)
				{
					return false;
				}
			}
			if (!TameAIPlugin.SocialVisits.Value)
			{
				return true;
			}
			if (state.NextSocial <= 0f)
			{
				state.NextSocial = time + 35f + StableFraction(((Object)ai).GetInstanceID(), 70f);
			}
			if (time >= state.NextSocial)
			{
				TryStartSocial(ai, character, state, time);
			}
			return state.Current == Mode.None;
		}

		private static void TryPlayerCuriosity(BaseAI ai, Character self, State state, float now)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: 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)
			float num = Mathf.Min(Mathf.Max(8f, ai.m_viewRange), TameAIPlugin.CuriosityMaxRange.Value);
			Player val = FindPlayerByInstance(state.DetectedPlayer);
			if ((Object)(object)val != (Object)null && !((Character)val).IsDead() && Vector3.Distance(((Component)self).transform.position, ((Component)val).transform.position) <= num + 5f)
			{
				return;
			}
			state.DetectedPlayer = 0;
			List<Player> allPlayers = Player.GetAllPlayers();
			Player val2 = null;
			float num2 = num * num;
			for (int i = 0; i < allPlayers.Count; i++)
			{
				Player val3 = allPlayers[i];
				if (!((Object)(object)val3 == (Object)null) && !((Character)val3).IsDead())
				{
					Vector3 val4 = ((Component)val3).transform.position - ((Component)self).transform.position;
					float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude;
					if (!(sqrMagnitude >= num2) && ai.CanSeeTarget((Character)(object)val3))
					{
						num2 = sqrMagnitude;
						val2 = val3;
					}
				}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			state.DetectedPlayer = ((Object)val2).GetInstanceID();
			if (StableFraction(((Object)ai).GetInstanceID() ^ ((Object)val2).GetInstanceID() ^ Mathf.FloorToInt(now), 100f) >= TameAIPlugin.CuriosityChance.Value)
			{
				return;
			}
			Vector3 val5 = ((Component)val2).transform.position - ((Component)self).transform.position;
			val5.y = 0f;
			if (!(((Vector3)(ref val5)).sqrMagnitude < 9f))
			{
				Vector3 val6 = ((Component)val2).transform.position - ((Vector3)(ref val5)).normalized * Mathf.Max(1.75f, self.GetRadius() + ((Character)val2).GetRadius() + 0.75f);
				float y = default(float);
				if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetSolidHeight(val6, ref y, 1000))
				{
					val6.y = y;
				}
				if (SafeTarget(ai, self, val6, allowOccupied: true))
				{
					state.Current = Mode.PlayerApproach;
					state.Target = val6;
					state.Until = now + 6f;
					state.NextPathCheck = now + 1f;
				}
			}
		}

		private static void TryStartSocial(BaseAI ai, Character self, State state, float now)
		{
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: 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_00cb: 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_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_00b2: Unknown result type (might be due to invalid IL or missing references)
			state.NextSocial = now + 55f + StableFraction(((Object)ai).GetInstanceID() + Mathf.FloorToInt(now), 85f);
			List<Character> allCharacters = Character.GetAllCharacters();
			Character val = null;
			float num = 144f;
			string prefabName = Utils.GetPrefabName(((Component)self).gameObject);
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val2 = allCharacters[i];
				if ((Object)(object)val2 == (Object)null || (Object)(object)val2 == (Object)(object)self || val2.IsDead() || !val2.IsTamed() || Utils.GetPrefabName(((Component)val2).gameObject) != prefabName)
				{
					continue;
				}
				BaseAI baseAI = val2.GetBaseAI();
				if (!((Object)(object)baseAI == (Object)null) && (!(baseAI is MonsterAI) || !((Object)(object)((MonsterAI)baseAI).GetFollowTarget() != (Object)null)))
				{
					Vector3 val3 = ((Component)val2).transform.position - ((Component)self).transform.position;
					float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
					if (!(sqrMagnitude < 9f) && !(sqrMagnitude > num))
					{
						num = sqrMagnitude;
						val = val2;
					}
				}
			}
			if (!((Object)(object)val == (Object)null))
			{
				Vector3 val4 = ((Component)val).transform.position - ((Component)self).transform.position;
				val4.y = 0f;
				Vector3 target = ((Component)val).transform.position - ((Vector3)(ref val4)).normalized * Mathf.Max(1.2f, self.GetRadius() + val.GetRadius() + 0.35f);
				if (SafeTarget(ai, self, target, allowOccupied: true))
				{
					state.Current = Mode.SocialApproach;
					state.SocialPartner = ((Object)val).GetInstanceID();
					state.Target = target;
					state.Until = now + 8f;
				}
			}
		}

		private static void EndSocial(BaseAI ai, State state, float now)
		{
			state.Current = Mode.None;
			state.SocialPartner = 0;
			state.NextSocial = now + 55f + StableFraction(((Object)ai).GetInstanceID() + Mathf.FloorToInt(now), 85f);
			ai.ResetRandomMovement();
		}

		private static void PickEscape(BaseAI ai, Character character, State state, Vector3 danger, float distance)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((Component)character).transform.position - danger;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				val = ((((Vector3)(ref state.HarmDirection)).sqrMagnitude > 0.01f) ? state.HarmDirection : ((Component)character).transform.forward);
			}
			((Vector3)(ref val)).Normalize();
			float[] array = new float[8] { 0f, 35f, -35f, 70f, -70f, 110f, -110f, 180f };
			float y = default(float);
			for (int i = 0; i < array.Length; i++)
			{
				Vector3 val2 = ((Component)character).transform.position + Quaternion.Euler(0f, array[i], 0f) * val * distance;
				if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetSolidHeight(val2, ref y, 1000))
				{
					val2.y = y;
				}
				if (SafeTarget(ai, character, val2))
				{
					state.Target = val2;
					return;
				}
			}
			state.Target = ((Component)character).transform.position;
		}

		private static bool SafeTarget(BaseAI ai, Character character, Vector3 target, bool allowOccupied = false)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = target - ((Component)character).transform.position;
			if (((Vector3)(ref val)).sqrMagnitude > 0.25f)
			{
				return HazardScanner.Judge(ai, character, target, allowOccupied) == RefusalReason.None;
			}
			return false;
		}

		private static Character FindByInstance(int id)
		{
			List<Character> allCharacters = Character.GetAllCharacters();
			for (int i = 0; i < allCharacters.Count; i++)
			{
				if ((Object)(object)allCharacters[i] != (Object)null && ((Object)allCharacters[i]).GetInstanceID() == id)
				{
					return allCharacters[i];
				}
			}
			return null;
		}

		private static Player FindPlayerByInstance(int id)
		{
			if (id == 0)
			{
				return null;
			}
			List<Player> allPlayers = Player.GetAllPlayers();
			for (int i = 0; i < allPlayers.Count; i++)
			{
				if ((Object)(object)allPlayers[i] != (Object)null && ((Object)allPlayers[i]).GetInstanceID() == id)
				{
					return allPlayers[i];
				}
			}
			return null;
		}

		private static State Get(BaseAI ai)
		{
			int instanceID = ((Object)ai).GetInstanceID();
			if (!States.TryGetValue(instanceID, out var value))
			{
				value = (States[instanceID] = new State());
			}
			return value;
		}

		private static float StableFraction(int seed, float range)
		{
			int num = seed ^ (seed << 13);
			int num2 = num ^ (num >>> 17);
			return (float)(uint)((num2 ^ (num2 << 5)) & 0xFFFF) / 65535f * range;
		}
	}
	[HarmonyPatch(typeof(BaseAI), "IdleMovement")]
	internal static class LocalIdleBehaviourPatch
	{
		private static bool Prefix(BaseAI __instance, float dt)
		{
			return LocalBehaviour.BeforeIdle(__instance, dt);
		}
	}
	[HarmonyPatch(typeof(BaseAI), "RandomMovement")]
	internal static class WanderAmplitudePatch
	{
		private static void Prefix(BaseAI __instance, ref float __state)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			__state = __instance.m_randomMoveRange;
			if (Authority.IsLocalParkedTame(__instance, out var character, out var _) && !Authority.IsCompanionAlpha(character) && LocalBehaviour.HasNearbyPlayer(((Component)character).transform.position))
			{
				__instance.m_randomMoveRange = __state * TameAIPlugin.WanderAmplitude.Value;
			}
		}

		private static void Postfix(BaseAI __instance, float __state)
		{
			__instance.m_randomMoveRange = __state;
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal static class EnvironmentalDamageResponsePatch
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			LocalBehaviour.EnvironmentalDamage(__instance, hit);
		}
	}
	internal static class PackFollowBehaviour
	{
		private sealed class State
		{
			internal Vector3 Target;

			internal Vector3 HarmDirection;

			internal float NextPlan;

			internal float NextSeparation;

			internal float NextHazardScan;

			internal float EscapeUntil;

			internal bool HasTarget;

			internal Vector3 Repulsion;
		}

		private static readonly Dictionary<int, State> States = new Dictionary<int, State>();

		private static readonly Func<BaseAI, float, Vector3, float, bool, bool> MoveTo = AccessTools.MethodDelegate<Func<BaseAI, float, Vector3, float, bool, bool>>(AccessTools.Method(typeof(BaseAI), "MoveTo", new Type[4]
		{
			typeof(float),
			typeof(Vector3),
			typeof(float),
			typeof(bool)
		}, (Type[])null), (object)null, true);

		private static readonly Action<BaseAI> StopMoving = AccessTools.MethodDelegate<Action<BaseAI>>(AccessTools.Method(typeof(BaseAI), "StopMoving", (Type[])null, (Type[])null), (object)null, true);

		internal static void Clear()
		{
			States.Clear();
		}

		internal static void Forget(BaseAI ai)
		{
			if ((Object)(object)ai != (Object)null)
			{
				States.Remove(((Object)ai).GetInstanceID());
			}
		}

		internal static bool Follow(BaseAI ai, GameObject follow, float dt)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_0204: 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_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			if (!TameAIPlugin.PackFollow.Value || !((Object)(object)follow != (Object)null) || !((Object)(object)follow.GetComponent<Player>() != (Object)null))
			{
				return false;
			}
			if (!Authority.IsLocalFollowingTame(ai, follow, out var character, out var _))
			{
				Forget(ai);
				return false;
			}
			State state = Get(ai);
			float time = Time.time;
			Vector3 position = ((Component)character).transform.position;
			Vector3 position2 = follow.transform.position;
			if (state.NextHazardScan <= time)
			{
				state.NextHazardScan = time + 0.7f + Fraction(((Object)ai).GetInstanceID(), 0.45f);
				if (HazardScanner.NearbyConstructedHazard(character, 7f, out var origin, out var keepAway, out var _) || HazardScanner.DangerAt(character, position, allowWater: true))
				{
					Vector3 val = position - ((origin == Vector3.zero) ? position2 : origin);
					val.y = 0f;
					if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
					{
						val = ((Component)character).transform.forward;
					}
					state.HarmDirection = ((Vector3)(ref val)).normalized;
					state.EscapeUntil = time + 1.5f;
					state.HasTarget = PickSafeTarget(ai, character, position, state.HarmDirection, Mathf.Clamp(keepAway + 1f, 4f, 8f), out state.Target);
				}
			}
			if (time < state.EscapeUntil)
			{
				if (!state.HasTarget)
				{
					StopMoving(ai);
					return true;
				}
				MoveTo(ai, dt, state.Target, 0.8f, arg5: false);
				return true;
			}
			float num = Mathf.Min(TameAIPlugin.PackInnerRadius.Value, TameAIPlugin.PackOuterRadius.Value - 1f);
			float num2 = Mathf.Max(num + 1f, TameAIPlugin.PackOuterRadius.Value);
			float num3 = HorizontalDistance(position, position2);
			float desired = character.GetRadius() + TameAIPlugin.PackSpacing.Value;
			if (time >= state.NextSeparation)
			{
				state.NextSeparation = time + 0.35f + Fraction(((Object)ai).GetInstanceID(), 0.25f);
				state.Repulsion = Separation(character, follow, desired);
			}
			Vector3 repulsion = state.Repulsion;
			bool flag = ((Vector3)(ref repulsion)).sqrMagnitude > 0.01f;
			if (num3 <= num2 && !flag)
			{
				state.HasTarget = false;
				StopMoving(ai);
				return true;
			}
			if (time >= state.NextPlan || !state.HasTarget)
			{
				state.NextPlan = time + 0.45f + Fraction(((Object)ai).GetInstanceID(), 0.25f);
				state.HasTarget = PlanFormationTarget(ai, character, follow, num, num2, repulsion, out state.Target);
			}
			if (!state.HasTarget)
			{
				StopMoving(ai);
				return true;
			}
			bool arg = num3 > num2 + 7f;
			if (MoveTo(ai, dt, state.Target, 1.1f, arg))
			{
				state.HasTarget = false;
			}
			return true;
		}

		internal static void Damage(Character character, HitData hit)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: 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_00ef: 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_00c9: 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_00d4: 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)
			if (!TameAIPlugin.PackFollow.Value || !TameAIPlugin.CalmHazardEscape.Value || (Object)(object)character == (Object)null || hit == null || !((DamageTypes)(ref hit.m_damage)).HaveDamage())
			{
				return;
			}
			BaseAI baseAI = character.GetBaseAI();
			MonsterAI val = (MonsterAI)(object)((baseAI is MonsterAI) ? baseAI : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val.GetFollowTarget() == (Object)null || !Authority.IsLocalFollowingTame(baseAI, val.GetFollowTarget(), out var _, out var _))
			{
				return;
			}
			Character attacker = hit.GetAttacker();
			if (!((Object)(object)attacker != (Object)null) || attacker is Player)
			{
				State state = Get(baseAI);
				Vector3 val2 = hit.m_dir;
				val2.y = 0f;
				if (((Vector3)(ref val2)).sqrMagnitude < 0.01f && hit.m_point != Vector3.zero)
				{
					val2 = ((Component)character).transform.position - hit.m_point;
				}
				if (((Vector3)(ref val2)).sqrMagnitude < 0.01f)
				{
					val2 = ((Component)character).transform.forward;
				}
				state.HarmDirection = ((Vector3)(ref val2)).normalized;
				state.EscapeUntil = Time.time + 1.5f;
				state.HasTarget = PickSafeTarget(baseAI, character, ((Component)character).transform.position, state.HarmDirection, 4f, out state.Target);
			}
		}

		private static bool PlanFormationTarget(BaseAI ai, Character character, GameObject follow, float inner, float outer, Vector3 repulsion, out Vector3 target)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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_0099: 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)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: 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_00f1: 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_00f4: 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_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_013c: 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_0117: 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_0124: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)character).transform.position;
			Vector3 position2 = follow.transform.position;
			Vector3 val = position - position2;
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.04f)
			{
				float num = Fraction(((Object)ai).GetInstanceID(), 360f);
				val = Quaternion.Euler(0f, num, 0f) * Vector3.forward;
			}
			((Vector3)(ref val)).Normalize();
			float num2 = Mathf.Lerp(inner, outer, Fraction(((Object)ai).GetInstanceID() * 31, 1f));
			Vector3 val2 = ((((Vector3)(ref repulsion)).sqrMagnitude > 0.01f) ? (((Vector3)(ref repulsion)).normalized * Mathf.Min(3.5f, ((Vector3)(ref repulsion)).magnitude)) : Vector3.zero);
			float[] array = new float[7] { 0f, 28f, -28f, 55f, -55f, 85f, -85f };
			for (int i = 0; i < array.Length; i++)
			{
				Vector3 val3 = Quaternion.Euler(0f, array[i], 0f) * val;
				Vector3 grounded = position2 + val3 * num2 + val2;
				if (TryGround(grounded, out grounded) && FormationSafe(character, position, grounded))
				{
					target = grounded;
					return true;
				}
			}
			target = position;
			return false;
		}

		private static bool PickSafeTarget(BaseAI ai, Character character, Vector3 origin, Vector3 direction, float distance, out Vector3 target)
		{
			//IL_0090: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			float[] array = new float[8] { 0f, 35f, -35f, 70f, -70f, 110f, -110f, 180f };
			for (int i = 0; i < 2; i++)
			{
				float num = ((i == 0) ? distance : Mathf.Min(9f, distance + 3f));
				for (int j = 0; j < array.Length; j++)
				{
					Vector3 grounded = origin + Quaternion.Euler(0f, array[j], 0f) * direction * num;
					if (TryGround(grounded, out grounded) && Safe(ai, character, origin, grounded))
					{
						target = grounded;
						return true;
					}
				}
			}
			target = origin;
			return false;
		}

		private static Vector3 Separation(Character self, GameObject follow, float desired)
		{
			//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_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00ee: 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_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.zero;
			List<Character> allCharacters = Character.GetAllCharacters();
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val2 = allCharacters[i];
				if ((Object)(object)val2 == (Object)null || (Object)(object)val2 == (Object)(object)self || val2.IsDead() || !val2.IsTamed())
				{
					continue;
				}
				BaseAI baseAI = val2.GetBaseAI();
				MonsterAI val3 = (MonsterAI)(object)((baseAI is MonsterAI) ? baseAI : null);
				if ((Object)(object)val3 == (Object)null || (Object)(object)val3.GetFollowTarget() != (Object)(object)follow)
				{
					continue;
				}
				Vector3 val4 = ((Component)self).transform.position - ((Component)val2).transform.position;
				val4.y = 0f;
				float num = desired + val2.GetRadius();
				float num2 = ((Vector3)(ref val4)).magnitude;
				if (!(num2 >= num))
				{
					if (num2 < 0.05f)
					{
						float num3 = ((((Object)self).GetInstanceID() < ((Object)val2).GetInstanceID()) ? (-1f) : 1f);
						val4 = Quaternion.Euler(0f, 90f * num3, 0f) * ((Component)self).transform.forward;
						num2 = 0.05f;
					}
					val += ((Vector3)(ref val4)).normalized * (num - num2);
				}
			}
			return val;
		}

		private static bool Safe(BaseAI ai, Character character, Vector3 from, Vector3 target)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (HazardScanner.Judge(ai, character, target, allowOccupied: true) == RefusalReason.None)
			{
				return HazardScanner.SafeFollowSegment(character, from, target);
			}
			return false;
		}

		private static bool FormationSafe(Character character, Vector3 from, Vector3 target)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (!HazardScanner.DangerAt(character, target, allowWater: true))
			{
				return HazardScanner.SafeFollowSegment(character, from, target, allowWater: true);
			}
			return false;
		}

		private static bool TryGround(Vector3 point, out Vector3 grounded)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			grounded = point;
			float y = default(float);
			if ((Object)(object)ZoneSystem.instance == (Object)null || !ZoneSystem.instance.GetSolidHeight(point, ref y, 1000))
			{
				return false;
			}
			grounded.y = y;
			return true;
		}

		private static float HorizontalDistance(Vector3 a, Vector3 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			float num = a.x - b.x;
			float num2 = a.z - b.z;
			return Mathf.Sqrt(num * num + num2 * num2);
		}

		private static State Get(BaseAI ai)
		{
			int instanceID = ((Object)ai).GetInstanceID();
			if (!States.TryGetValue(instanceID, out var value))
			{
				value = (States[instanceID] = new State());
			}
			return value;
		}

		private static float Fraction(int seed, float range)
		{
			int num = seed ^ (seed << 13);
			int num2 = num ^ (num >>> 17);
			return (float)(uint)((num2 ^ (num2 << 5)) & 0xFFFF) / 65535f * range;
		}
	}
	[HarmonyPatch(typeof(BaseAI), "Follow")]
	internal static class PackFollowPatch
	{
		private static bool Prefix(BaseAI __instance, GameObject go, float dt)
		{
			return !PackFollowBehaviour.Follow(__instance, go, dt);
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal static class PackFollowDamagePatch
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			PackFollowBehaviour.Damage(__instance, hit);
		}
	}
	[HarmonyPatch(typeof(MonsterAI), "SetFollowTarget")]
	internal static class ResetPackFollowTargetPatch
	{
		private static void Postfix(MonsterAI __instance)
		{
			PackFollowBehaviour.Forget((BaseAI)(object)__instance);
			if (!((Object)(object)__instance == (Object)null) && TameAIPlugin.AvoidSwimming.Value)
			{
				((BaseAI)__instance).m_avoidWater = (Object)(object)__instance.GetFollowTarget() == (Object)null;
			}
		}
	}
	[BepInPlugin("nicomods.tameai", "NicoMods TameAI", "1.1.6")]
	public sealed class TameAIPlugin : BaseUnityPlugin
	{
		public const string Guid = "nicomods.tameai";

		public const string Name = "NicoMods TameAI";

		public const string Version = "1.1.6";

		internal static TameAIPlugin Instance;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> ImproveWandering;

		internal static ConfigEntry<bool> StuckRecovery;

		internal static ConfigEntry<bool> AnimalSeparation;

		internal static ConfigEntry<bool> StructureAwareness;

		internal static ConfigEntry<bool> AvoidSwimming;

		internal static ConfigEntry<bool> AvoidFire;

		internal static ConfigEntry<bool> AvoidLava;

		internal static ConfigEntry<bool> AvoidSmoke;

		internal static ConfigEntry<bool> AvoidTraps;

		internal static ConfigEntry<bool> Diagnostics;

		internal static ConfigEntry<float> StructureMargin;

		internal static ConfigEntry<float> SeparationMargin;

		internal static ConfigEntry<float> RestingClearance;

		internal static ConfigEntry<float> StuckSeconds;

		internal static ConfigEntry<float> WanderAmplitude;

		internal static ConfigEntry<bool> CalmHazardEscape;

		internal static ConfigEntry<bool> SocialVisits;

		internal static ConfigEntry<bool> PlayerCuriosity;

		internal static ConfigEntry<float> CuriosityChance;

		internal static ConfigEntry<float> CuriosityMaxRange;

		internal static ConfigEntry<bool> PackFollow;

		internal static ConfigEntry<float> PackInnerRadius;

		internal static ConfigEntry<float> PackOuterRadius;

		internal static ConfigEntry<float> PackSpacing;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Expected O, but got Unknown
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Expected O, but got Unknown
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Expected O, but got Unknown
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Expected O, but got Unknown
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Expected O, but got Unknown
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Expected O, but got Unknown
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Expected O, but got Unknown
			//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Expected O, but got Unknown
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Expected O, but got Unknown
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			//IL_0443: Expected O, but got Unknown
			//IL_044e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Expected O, but got Unknown
			Instance = this;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. Off leaves vanilla behaviour untouched.");
			ImproveWandering = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ImproveWandering", true, "Reject unsafe or unreachable ordinary wander destinations.");
			StuckRecovery = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "StuckRecovery", true, "Abandon an ordinary wander destination after sustained lack of progress.");
			AnimalSeparation = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AnimalSeparation", true, "Avoid choosing a resting destination already occupied by another creature.");
			StructureAwareness = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "StructureAwareness", true, "Reject wander paths blocked by walls, fences or openings too small for the creature.");
			AvoidSwimming = ((BaseUnityPlugin)this).Config.Bind<bool>("Water", "AvoidSwimming", true, "Land creatures do not deliberately choose an ordinary wander destination in deep water.");
			AvoidFire = ((BaseUnityPlugin)this).Config.Bind<bool>("Hazards", "AvoidFire", true, "Enable vanilla fire avoidance flags for parked tames and reject fire destinations.");
			AvoidLava = ((BaseUnityPlugin)this).Config.Bind<bool>("Hazards", "AvoidLava", true, "Enable vanilla lava avoidance and reject lava destinations.");
			AvoidSmoke = ((BaseUnityPlugin)this).Config.Bind<bool>("Hazards", "AvoidSmoke", true, "Reject ordinary wander destinations inside smoke.");
			AvoidTraps = ((BaseUnityPlugin)this).Config.Bind<bool>("Hazards", "AvoidTraps", true, "Reject destinations near an AOE that damages friendly characters.");
			Diagnostics = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "Diagnostics", false, "Log deduplicated refusals and stuck recoveries for testing.");
			StructureMargin = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "StructureMargin", 0.2f, new ConfigDescription("Extra clearance around the creature for structure checks, metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1.5f), Array.Empty<object>()));
			SeparationMargin = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "SeparationMargin", 0.35f, new ConfigDescription("Extra personal space used only while choosing wander destinations, metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
			RestingClearance = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "RestingClearance", 2f, new ConfigDescription("Minimum horizontal clearance from vertical player-built pieces for an idle resting destination, metres. Floors below the animal are allowed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 5f), Array.Empty<object>()));
			StuckSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "StuckSeconds", 3f, new ConfigDescription("Seconds with negligible progress before an ordinary wander is abandoned.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
			WanderAmplitude = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "WanderAmplitude", 1.15f, new ConfigDescription("Small multiplier applied only to ordinary tame wandering.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 1.5f), Array.Empty<object>()));
			CalmHazardEscape = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "CalmHazardEscape", true, "Walk a short safe distance away from damaging environment and constructed defences.");
			SocialVisits = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SocialVisits", true, "Occasionally let an idle tame approach a nearby tame of the same species.");
			PlayerCuriosity = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PlayerCuriosity", true, "Give an idle tame one small chance to walk toward a player it has just detected; never creates Follow.");
			CuriosityChance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CuriosityChance", 10f, new ConfigDescription("Chance per newly detected player, percent. No retry until that player leaves detection range.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 25f), Array.Empty<object>()));
			CuriosityMaxRange = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "CuriosityMaxRange", 20f, new ConfigDescription("Maximum range used for calm player curiosity, metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 40f), Array.Empty<object>()));
			PackFollow = ((BaseUnityPlugin)this).Config.Bind<bool>("Follow", "PackFollow", true, "Replace direct-to-player tame Follow with a spaced, hazard-aware area formation.");
			PackInnerRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Follow", "PackInnerRadius", 5f, new ConfigDescription("Preferred minimum distance from the followed player, metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 12f), Array.Empty<object>()));
			PackOuterRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Follow", "PackOuterRadius", 11f, new ConfigDescription("Preferred outer formation radius around the followed player, metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(6f, 20f), Array.Empty<object>()));
			PackSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("Follow", "PackSpacing", 2.5f, new ConfigDescription("Extra spacing sought between following tames, metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 6f), Array.Empty<object>()));
			harmony = new Harmony("nicomods.tameai");
			harmony.PatchAll(typeof(TameAIPlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"NicoMods TameAI 1.1.6 loaded; local-owner navigation safeguards active.");
		}

		private void OnDestroy()
		{
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			WanderSafety.Clear();
			LocalBehaviour.Clear();
			PackFollowBehaviour.Clear();
			Instance = null;
		}

		internal static void DebugLog(string text)
		{
			if ((Object)(object)Instance != (Object)null && Diagnostics != null && Diagnostics.Value)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[TameAI] " + text));
			}
		}
	}
	internal static class WanderSafety
	{
		private sealed class State
		{
			internal Vector3 Destination;

			internal Vector3 LastPosition;

			internal float LastDistance;

			internal float StalledFor;

			internal float LastLog;

			internal RefusalReason LastReason;
		}

		private static readonly Dictionary<int, State> States = new Dictionary<int, State>();

		private static readonly FieldInfo RandomTarget = AccessTools.Field(typeof(BaseAI), "m_randomMoveTarget");

		private static readonly FieldInfo Reached = AccessTools.Field(typeof(BaseAI), "m_reachedRandomMoveTarget");

		internal static void Clear()
		{
			States.Clear();
		}

		internal static bool IsCurrentWander(BaseAI ai, Vector3 point)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (RandomTarget == null || Reached == null)
			{
				return false;
			}
			Vector3 val = (Vector3)RandomTarget.GetValue(ai);
			if (!(bool)Reached.GetValue(ai))
			{
				Vector3 val2 = val - point;
				return ((Vector3)(ref val2)).sqrMagnitude < 0.04f;
			}
			return false;
		}

		internal static void Observe(BaseAI ai, Character character, Vector3 destination, float dt, bool arrived)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			if (!TameAIPlugin.StuckRecovery.Value || arrived)
			{
				Forget(ai);
				return;
			}
			int instanceID = ((Object)ai).GetInstanceID();
			if (States.TryGetValue(instanceID, out var value))
			{
				Vector3 val = value.Destination - destination;
				if (!(((Vector3)(ref val)).sqrMagnitude > 0.25f))
				{
					float num = DistanceXZ(value.LastPosition, ((Component)character).transform.position);
					float num2 = DistanceXZ(((Component)character).transform.position, destination);
					float num3 = value.LastDistance - num2;
					if (num < 0.05f && num3 < 0.03f)
					{
						value.StalledFor += Mathf.Max(0f, dt);
					}
					else
					{
						value.StalledFor = Mathf.Max(0f, value.StalledFor - dt * 2f);
					}
					value.LastPosition = ((Component)character).transform.position;
					value.LastDistance = num2;
					if (!(value.StalledFor < TameAIPlugin.StuckSeconds.Value))
					{
						ai.ResetRandomMovement();
						States.Remove(instanceID);
						TameAIPlugin.DebugLog(character.m_name + " abandoned a blocked wander destination after " + TameAIPlugin.StuckSeconds.Value.ToString("0.0") + " s.");
					}
					return;
				}
			}
			States[instanceID] = new State
			{
				Destination = destination,
				LastPosition = ((Component)character).transform.position,
				LastDistance = DistanceXZ(((Component)character).transform.position, destination)
			};
		}

		internal static void Refused(BaseAI ai, Character character, RefusalReason reason)
		{
			int instanceID = ((Object)ai).GetInstanceID();
			if (!States.TryGetValue(instanceID, out var value))
			{
				value = (States[instanceID] = new State());
			}
			float time = Time.time;
			if (value.LastReason != reason || time - value.LastLog >= 10f)
			{
				value.LastReason = reason;
				value.LastLog = time;
				TameAIPlugin.DebugLog(character.m_name + " wander destination refused: " + reason.ToString() + ".");
			}
		}

		internal static void Forget(BaseAI ai)
		{
			if ((Object)(object)ai != (Object)null)
			{
				States.Remove(((Object)ai).GetInstanceID());
			}
		}

		private static float DistanceXZ(Vector3 a, Vector3 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			float num = a.x - b.x;
			float num2 = a.z - b.z;
			return Mathf.Sqrt(num * num + num2 * num2);
		}
	}
	[HarmonyPatch(typeof(BaseAI), "IsValidRandomMovePoint")]
	internal static class ValidateWanderDestinationPatch
	{
		private static void Postfix(BaseAI __instance, Vector3 point, ref bool __result)
		{
			//IL_0026: 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)
			if (__result && TameAIPlugin.ImproveWandering.Value && Authority.IsLocalParkedTame(__instance, out var character, out var _))
			{
				HazardScanner.ArmVanilla(__instance);
				RefusalReason refusalReason = HazardScanner.Judge(__instance, character, point);
				if (refusalReason == RefusalReason.None)
				{
					refusalReason = HazardScanner.JudgeRestingArea(character, point);
				}
				if (refusalReason != RefusalReason.None)
				{
					__result = false;
					WanderSafety.Refused(__instance, character, refusalReason);
				}
			}
		}
	}
	[HarmonyPatch(typeof(BaseAI), "MoveTo")]
	internal static class WanderProgressPatch
	{
		private static void Postfix(BaseAI __instance, float dt, Vector3 point, bool __result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (!WanderSafety.IsCurrentWander(__instance, point))
			{
				return;
			}
			if (!Authority.IsLocalParkedTame(__instance, out var character, out var _))
			{
				WanderSafety.Forget(__instance);
				return;
			}
			if (__result)
			{
				RefusalReason refusalReason = HazardScanner.JudgeRestingArea(character, point);
				if (refusalReason != RefusalReason.None)
				{
					__instance.ResetRandomMovement();
					WanderSafety.Refused(__instance, character, refusalReason);
					return;
				}
			}
			WanderSafety.Observe(__instance, character, point, dt, __result);
		}
	}
	[HarmonyPatch(typeof(BaseAI), "OnDestroy")]
	internal static class ForgetDestroyedAiPatch
	{
		private static void Prefix(BaseAI __instance)
		{
			WanderSafety.Forget(__instance);
			LocalBehaviour.Forget(__instance);
			PackFollowBehaviour.Forget(__instance);
		}
	}
	[HarmonyPatch(typeof(BaseAI), "Awake")]
	internal static class ArmExistingTamePatch
	{
		private static void Postfix(BaseAI __instance)
		{
			if (Authority.IsLocalParkedTame(__instance, out var _, out var _))
			{
				HazardScanner.ArmVanilla(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "SetTamed")]
	internal static class ArmNewTamePatch
	{
		private static void Postfix(Character __instance, bool tamed)
		{
			if (tamed && !((Object)(object)__instance == (Object)null))
			{
				BaseAI baseAI = __instance.GetBaseAI();
				if (Authority.IsLocalParkedTame(baseAI, out var _, out var _))
				{
					HazardScanner.ArmVanilla(baseAI);
				}
			}
		}
	}
}