Decompiled source of MuchBetterTames v1.8.0

MuchBetterTames.dll

Decompiled 14 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.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 TameCompanions
{
	internal class CompanionController : MonoBehaviour
	{
		private struct Throttle
		{
			private float _t;

			public bool Check(float dt)
			{
				_t += dt;
				if (_t < 0.05f)
				{
					return false;
				}
				_t = 0f;
				return true;
			}
		}

		private sealed class FieldRef
		{
			public object Obj;

			public FieldInfo F;

			public string Key;

			public object Val;
		}

		private sealed class Snap
		{
			public readonly List<FieldRef> Fields = new List<FieldRef>();

			public readonly Dictionary<Behaviour, bool> Enabled = new Dictionary<Behaviour, bool>();

			public bool HasRb;

			public bool RbKin;

			public bool RbGrav;

			public bool RbDetect;

			public RigidbodyConstraints RbConstraints;

			public bool HasAnim;

			public bool AnimOn;

			public bool AnimRoot;

			public float AnimSpeed;
		}

		internal static readonly List<CompanionController> All = new List<CompanionController>();

		internal static readonly Dictionary<Character, CompanionController> ByCharacter = new Dictionary<Character, CompanionController>();

		internal static readonly Dictionary<BaseAI, CompanionController> ByAi = new Dictionary<BaseAI, CompanionController>();

		internal const string K_Leader = "TC_Leader";

		internal const string K_DownLeft = "TC_DownLeft";

		internal const string K_DownStamp = "TC_DownStamp";

		internal const string K_Xp = "TC_Xp";

		internal const string K_Level = "TC_Level";

		internal const string K_Snap = "TC_Snap";

		internal const string K_RecStamp = "TC_RecStamp";

		internal static readonly int H_Leader = StringExtensionMethods.GetStableHashCode("TC_Leader");

		private static readonly MethodInfo IsHungryMethod = AccessTools.Method(typeof(Tameable), "IsHungry", (Type[])null, (Type[])null);

		internal Character Ch;

		internal MonsterAI Ai;

		internal Tameable Tm;

		internal ZNetView Nv;

		internal float LastToggle = -999f;

		internal bool Aboard;

		private bool _holding;

		private float _nextBoard;

		private float _radius = -1f;

		private float _lockUntil;

		private Rigidbody _rb;

		private Animator _anim;

		private ZSyncAnimation _zanim;

		private float _acc;

		private float _lastHp;

		private float _lastDamageTime = -999f;

		private float _farTime;

		private bool _aiOffByUs;

		private bool _errLogged;

		private bool _inited;

		private Vector3 _lastPos;

		private float _stuckTime;

		private int _softResets;

		private int _sleepParam;

		private float _butcherUntil;

		private Vector3 _tickPos;

		private float _lastMovedTime;

		private float _nextSnap;

		private Snap _snap;

		private float _recoverCheckUntil;

		private float _standUntil;

		private Throttle _downedTick;

		private float _recoverAt = -1f;

		private Vector3 _recoverPos;

		private bool _rebindDone;

		private static readonly FieldInfo SleepingField = AccessTools.Field(typeof(MonsterAI), "m_sleeping");

		private bool _visualDown;

		private readonly Dictionary<string, bool> _paramCache = new Dictionary<string, bool>();

		private float _nextRescue;

		private float _embeddedTime;

		private static int _embedMask = -1;

		private static readonly MethodInfo WakeupMethod = AccessTools.Method(typeof(MonsterAI), "Wakeup", (Type[])null, (Type[])null);

		internal long LeaderId => ((Object)(object)Nv != (Object)null && Nv.GetZDO() != null) ? Nv.GetZDO().GetLong("TC_Leader", 0L) : 0;

		internal float DownLeft => ((Object)(object)Nv != (Object)null && Nv.GetZDO() != null) ? Nv.GetZDO().GetFloat("TC_DownLeft", 0f) : 0f;

		internal bool IsDowned => DownLeft > 0f;

		internal bool ActionLocked
		{
			get
			{
				float value = Cfg.RecoverLockSeconds.Value;
				if (value <= 0f)
				{
					return false;
				}
				if (Time.time < _lockUntil)
				{
					return true;
				}
				ZDO val = (((Object)(object)Nv != (Object)null) ? Nv.GetZDO() : null);
				if (val == null || (Object)(object)ZNet.instance == (Object)null)
				{
					return false;
				}
				long num = val.GetLong("TC_RecStamp", 0L);
				if (num == 0)
				{
					return false;
				}
				return NowMs() - num < (long)(value * 1000f);
			}
		}

		internal bool RecoverProtected
		{
			get
			{
				float value = Cfg.RecoverProtectSeconds.Value;
				if (value <= 0f)
				{
					return false;
				}
				ZDO val = (((Object)(object)Nv != (Object)null) ? Nv.GetZDO() : null);
				if (val == null || (Object)(object)ZNet.instance == (Object)null)
				{
					return false;
				}
				long num = val.GetLong("TC_RecStamp", 0L);
				return num != 0L && NowMs() - num < (long)(value * 1000f);
			}
		}

		private float BodyRadius
		{
			get
			{
				//IL_003d: 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_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_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				if (_radius < 0f)
				{
					_radius = 0.4f;
					try
					{
						Collider val = ((Component)this).GetComponent<Collider>() ?? ((Component)this).GetComponentInChildren<Collider>();
						if ((Object)(object)val != (Object)null)
						{
							Bounds bounds = val.bounds;
							Vector3 extents = ((Bounds)(ref bounds)).extents;
							_radius = Mathf.Clamp(Mathf.Max(extents.x, extents.z) * 0.8f, 0.3f, 2.5f);
						}
					}
					catch
					{
					}
				}
				return _radius;
			}
		}

		internal bool ButcherActive => Time.time < _butcherUntil;

		private void Awake()
		{
			Nv = ((Component)this).GetComponent<ZNetView>();
			Ch = ((Component)this).GetComponent<Character>();
			Ai = ((Component)this).GetComponent<MonsterAI>();
			Tm = ((Component)this).GetComponent<Tameable>();
			_rb = ((Component)this).GetComponent<Rigidbody>();
			_zanim = ((Component)this).GetComponent<ZSyncAnimation>();
			_anim = ((Component)this).GetComponentInChildren<Animator>();
			if ((Object)(object)Nv == (Object)null || (Object)(object)Ch == (Object)null || (Object)(object)Ai == (Object)null || (Object)(object)Tm == (Object)null)
			{
				((Behaviour)this).enabled = false;
			}
			else
			{
				TryInit();
			}
		}

		private void TryInit()
		{
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			if (!_inited && !((Object)(object)Nv == (Object)null) && Nv.IsValid())
			{
				_inited = true;
				Nv.Register<float>("TC_AddXp", (Action<long, float>)RPC_AddXp);
				Nv.Register<float>("TC_Help", (Action<long, float>)RPC_Help);
				Nv.Register("TC_Butcher", (Action<long>)RPC_Butcher);
				All.Add(this);
				ByCharacter[Ch] = this;
				ByAi[(BaseAI)(object)Ai] = this;
				_lastHp = Ch.GetHealth();
				_lastPos = ((Component)this).transform.position;
			}
		}

		private void OnDestroy()
		{
			All.Remove(this);
			if (Ch != null)
			{
				ByCharacter.Remove(Ch);
			}
			if (Ai != null)
			{
				ByAi.Remove((BaseAI)(object)Ai);
			}
		}

		private void Update()
		{
			if (!_inited)
			{
				TryInit();
				if (!_inited)
				{
					return;
				}
			}
			if ((Object)(object)Nv == (Object)null || !Nv.IsValid())
			{
				return;
			}
			ApplyDownVisual(IsDowned);
			if (_downedTick.Check(Time.deltaTime) && Cfg.Enabled.Value && Nv.IsOwner() && IsDowned && Ch.IsTamed() && DownedWillEnd())
			{
				try
				{
					if ((Object)(object)ZNet.instance != (Object)null)
					{
						TickDowned(0f);
					}
				}
				catch
				{
				}
			}
			_acc += Time.deltaTime;
			if (_acc < 0.5f)
			{
				return;
			}
			float acc = _acc;
			_acc = 0f;
			SyncLevelVisual();
			if (!Cfg.Enabled.Value || !Ch.IsTamed() || !Nv.IsOwner())
			{
				return;
			}
			try
			{
				OwnerTick(acc);
			}
			catch (Exception ex)
			{
				if (!_errLogged)
				{
					_errLogged = true;
					TameCompanionsPlugin.Log.LogWarning((object)("Controller-Fehler: " + ex));
				}
			}
		}

		private void OwnerTick(float dt)
		{
			//IL_00dd: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null || TickDowned(dt))
			{
				return;
			}
			if (!((Behaviour)Ai).enabled)
			{
				((Behaviour)Ai).enabled = true;
			}
			_aiOffByUs = false;
			if (Time.time < _recoverCheckUntil)
			{
				try
				{
					if (IsStillLying())
					{
						TameCompanionsPlugin.Log.LogInfo((object)("Rest-Knockdown nach Erholung bereinigt: " + ((Object)this).name + " | " + DumpState()));
						_visualDown = false;
						ForceAwake();
						SetSleepAnim(on: false);
						if (!_rebindDone)
						{
							_rebindDone = true;
							ResetAnimator();
						}
					}
				}
				catch
				{
				}
			}
			Vector3 position = ((Component)this).transform.position;
			Vector3 val = position - _tickPos;
			if (((Vector3)(ref val)).sqrMagnitude > 0.25f)
			{
				_lastMovedTime = Time.time;
			}
			_tickPos = position;
			if (Time.time >= _nextSnap)
			{
				_nextSnap = Time.time + 10f;
				if (Time.time - _lastMovedTime < 3f && Time.time > _recoverCheckUntil + 30f && Time.time - _lastDamageTime > 15f && (Object)(object)((BaseAI)Ai).GetTargetCreature() == (Object)null && ((Behaviour)Ai).enabled)
				{
					try
					{
						_snap = Capture();
					}
					catch
					{
					}
				}
			}
			float health = Ch.GetHealth();
			if (health < _lastHp - 0.01f)
			{
				_lastDamageTime = Time.time;
			}
			bool inCombat = Time.time - _lastDamageTime < Cfg.CombatCooldown.Value || (Object)(object)((BaseAI)Ai).GetTargetCreature() != (Object)null;
			if (Cfg.RegenEnabled.Value)
			{
				Regen(dt, inCombat);
			}
			_lastHp = Ch.GetHealth();
			FollowAndTeleport(dt);
		}

		internal bool FollowsPlayer(Player p)
		{
			long leaderId = LeaderId;
			if (leaderId != 0)
			{
				return leaderId == p.GetPlayerID();
			}
			return Nv.IsOwner() && (Object)(object)Ai.GetFollowTarget() == (Object)(object)((Component)p).gameObject;
		}

		private static long NowMs()
		{
			return (long)(ZNet.instance.GetTimeSeconds() * 1000.0);
		}

		internal static bool IsDownedTame(Character c)
		{
			if ((Object)(object)c == (Object)null || !c.IsTamed())
			{
				return false;
			}
			CompanionController value;
			return ByCharacter.TryGetValue(c, out value) && (Object)(object)value != (Object)null && value.IsDowned;
		}

		internal static Player FindPlayer(long id)
		{
			if (id == 0)
			{
				return null;
			}
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if ((Object)(object)allPlayer != (Object)null && allPlayer.GetPlayerID() == id)
				{
					return allPlayer;
				}
			}
			return null;
		}

		private bool SafeHungry()
		{
			try
			{
				return IsHungryMethod != null && (bool)IsHungryMethod.Invoke(Tm, null);
			}
			catch
			{
				return false;
			}
		}

		internal void SetFollow(Player p, bool follow)
		{
			Nv.ClaimOwnership();
			if (follow)
			{
				((BaseAI)Ai).ResetPatrolPoint();
				Ai.SetFollowTarget(((Component)p).gameObject);
				Nv.GetZDO().Set("TC_Leader", p.GetPlayerID());
			}
			else
			{
				Ai.SetFollowTarget((GameObject)null);
				((BaseAI)Ai).SetPatrolPoint();
				Nv.GetZDO().Set("TC_Leader", 0L);
			}
		}

		private void FollowAndTeleport(float dt)
		{
			//IL_00e4: 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_00a2: 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_0126: 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_0133: 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_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: 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_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: 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_02c7: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = Nv.GetZDO();
			if (zDO == null)
			{
				return;
			}
			long num = zDO.GetLong("TC_Leader", 0L);
			GameObject followTarget = Ai.GetFollowTarget();
			if (num == 0)
			{
				Player val = (((Object)(object)followTarget != (Object)null) ? followTarget.GetComponent<Player>() : null);
				if (!((Object)(object)val != (Object)null))
				{
					_farTime = 0f;
					_stuckTime = 0f;
					_softResets = 0;
					_lastPos = ((Component)this).transform.position;
					return;
				}
				num = val.GetPlayerID();
				zDO.Set("TC_Leader", num);
			}
			Player val2 = FindPlayer(num);
			if ((Object)(object)val2 == (Object)null || ((Character)val2).IsDead())
			{
				_stuckTime = 0f;
				_lastPos = ((Component)this).transform.position;
				return;
			}
			if ((Object)(object)followTarget == (Object)null)
			{
				((BaseAI)Ai).ResetPatrolPoint();
				Ai.SetFollowTarget(((Component)val2).gameObject);
			}
			Vector3 position = ((Component)val2).transform.position;
			Vector3 position2 = ((Component)this).transform.position;
			bool flag = position.y > 3000f;
			if (flag && (!Cfg.FollowDungeons.Value || CompanionManager.IsDungeonExcluded(((Component)this).gameObject)))
			{
				_stuckTime = 0f;
				_lastPos = position2;
				return;
			}
			float num2 = Vector3.Distance(position, position2);
			if (zDO.GetBool("TC_Snap", false))
			{
				zDO.Set("TC_Snap", false);
				TeleportBehind(val2);
				return;
			}
			if (Time.time >= _nextRescue && IsLost(dt, flag, out var why))
			{
				_nextRescue = Time.time + 3f;
				TameCompanionsPlugin.Log.LogInfo((object)("Verloren/Eingeklemmt (" + why + "): " + ((Object)this).name + " -> hinter den Spieler gesetzt | " + DumpState()));
				TeleportBehind(val2);
				return;
			}
			bool flag2 = (Object)(object)((BaseAI)Ai).GetTargetCreature() != (Object)null;
			Ship val3 = (Cfg.ShipEnabled.Value ? ShipHelper.ShipOf(val2) : null);
			if ((Object)(object)val3 != (Object)null)
			{
				Aboard = ShipHelper.IsAboard(position2, val3);
				if (Aboard)
				{
					_farTime = 0f;
					_stuckTime = 0f;
					_softResets = 0;
					_lastPos = position2;
					return;
				}
				if (Cfg.TeleportEnabled.Value && Time.time >= _nextBoard && !ShipHelper.Excluded(((Component)this).gameObject) && (!flag2 || !(num2 < Cfg.CombatTeleportDistance.Value)) && (num2 > Cfg.ShipBoardDistance.Value || ShipHelper.IsMoving(val3)))
				{
					_nextBoard = Time.time + 3f;
					TeleportBehind(val2);
					return;
				}
			}
			else
			{
				Aboard = false;
			}
			if (UpdateStuck(dt, num2, flag2, val2) || !Cfg.TeleportEnabled.Value)
			{
				return;
			}
			if (flag2 && num2 < Cfg.CombatTeleportDistance.Value)
			{
				_farTime = 0f;
				return;
			}
			float num3 = (flag ? Cfg.DungeonTeleportDistance.Value : Cfg.TeleportDistance.Value);
			bool flag3 = num2 > num3;
			if (!flag3)
			{
				if (num2 > 15f)
				{
					_farTime += dt;
				}
				else
				{
					_farTime = 0f;
				}
				if (_farTime >= Cfg.StuckSeconds.Value)
				{
					flag3 = true;
				}
			}
			if (flag3)
			{
				_farTime = 0f;
				TeleportBehind(val2);
			}
		}

		private bool UpdateStuck(float dt, float dist, bool fighting, Player leader)
		{
			//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_000d: 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_0014: 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_0024: 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_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)
			Vector3 position = ((Component)this).transform.position;
			Vector3 val = position - _lastPos;
			float magnitude = ((Vector3)(ref val)).magnitude;
			_lastPos = position;
			bool flag = false;
			try
			{
				val = Traverse.Create((object)Ch).Field("m_moveDir").GetValue<Vector3>();
				flag = ((Vector3)(ref val)).sqrMagnitude > 0.01f;
			}
			catch
			{
			}
			if (fighting || !(magnitude < 0.2f) || (!(dist > 6f) && !(dist > 3.5f && flag)))
			{
				_stuckTime = 0f;
				_softResets = 0;
				return false;
			}
			_stuckTime += dt;
			if (_stuckTime >= 2f && _softResets == 0)
			{
				_softResets = 1;
				TameCompanionsPlugin.Log.LogInfo((object)("Festhänger-Reset (Stufe 1): " + ((Object)this).name + " | " + DumpState()));
				SoftReset(leader);
				return false;
			}
			if (_stuckTime >= 4f && _softResets == 1)
			{
				_softResets = 2;
				TameCompanionsPlugin.Log.LogInfo((object)("Festhänger-Reset (Stufe 2): " + ((Object)this).name + " | " + DumpState()));
				HardReset(leader);
				return false;
			}
			if (_stuckTime >= 6.5f)
			{
				_stuckTime = 0f;
				_softResets = 0;
				TameCompanionsPlugin.Log.LogInfo((object)("Festhänger (Stufe 3): " + ((Object)this).name + " | " + DumpState()));
				if (Cfg.TeleportEnabled.Value && dist > Cfg.NoTeleportNear.Value)
				{
					TeleportBehind(leader);
					return true;
				}
				HardReset(leader);
			}
			return false;
		}

		private void SoftReset(Player leader)
		{
			//IL_0049: 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)
			try
			{
				((BaseAI)Ai).StopMoving();
			}
			catch
			{
			}
			ForceAwake();
			ResetAnimator();
			if ((Object)(object)_rb != (Object)null)
			{
				_rb.isKinematic = false;
				_rb.velocity = Vector3.zero;
				_rb.angularVelocity = Vector3.zero;
				_rb.WakeUp();
			}
			((Behaviour)Ai).enabled = false;
			((Behaviour)Ai).enabled = true;
			_aiOffByUs = false;
			((BaseAI)Ai).ResetPatrolPoint();
			Ai.SetFollowTarget(((Component)leader).gameObject);
		}

		private void HardReset(Player leader)
		{
			//IL_005b: 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)
			SoftReset(leader);
			ClearStatusEffects();
			try
			{
				DiffAndRestore(restore: true);
			}
			catch (Exception ex)
			{
				TameCompanionsPlugin.Log.LogWarning((object)("Zustandsvergleich: " + ex.Message));
			}
			try
			{
				if ((Object)(object)_rb != (Object)null)
				{
					_rb.constraints = (RigidbodyConstraints)(_rb.constraints & -15);
					_rb.detectCollisions = true;
				}
				if ((Object)(object)_anim != (Object)null)
				{
					((Behaviour)_anim).enabled = true;
					_anim.speed = 1f;
				}
				ZSyncTransform component = ((Component)this).GetComponent<ZSyncTransform>();
				if ((Object)(object)component != (Object)null)
				{
					((Behaviour)component).enabled = true;
				}
				if ((Object)(object)Ch != (Object)null)
				{
					((Behaviour)Ch).enabled = true;
				}
			}
			catch
			{
			}
		}

		private void ClearStatusEffects()
		{
			try
			{
				object value = Traverse.Create((object)Ch).Field("m_seman").GetValue();
				if (value == null)
				{
					return;
				}
				MethodInfo[] methods = value.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (MethodInfo methodInfo in methods)
				{
					if (!(methodInfo.Name != "RemoveAllStatusEffects"))
					{
						ParameterInfo[] parameters = methodInfo.GetParameters();
						methodInfo.Invoke(value, (parameters.Length == 0) ? null : new object[1] { true });
						break;
					}
				}
			}
			catch
			{
			}
		}

		private static bool Simple(Type t)
		{
			return t == typeof(bool) || t == typeof(int) || t == typeof(float) || t.IsEnum;
		}

		private Snap Capture()
		{
			//IL_01ff: 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)
			Snap snap = new Snap();
			object[] array = new object[3] { Ch, Ai, Tm };
			object[] array2 = array;
			foreach (object obj in array2)
			{
				if (obj == null)
				{
					continue;
				}
				Type type = obj.GetType();
				Type type2 = type;
				while (type2 != null && type2 != typeof(MonoBehaviour))
				{
					FieldInfo[] fields = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (FieldInfo fieldInfo in fields)
					{
						if (Simple(fieldInfo.FieldType))
						{
							try
							{
								snap.Fields.Add(new FieldRef
								{
									Obj = obj,
									F = fieldInfo,
									Key = type.Name + "." + type2.Name + "." + fieldInfo.Name,
									Val = fieldInfo.GetValue(obj)
								});
							}
							catch
							{
							}
						}
					}
					type2 = type2.BaseType;
				}
			}
			Behaviour[] componentsInChildren = ((Component)this).GetComponentsInChildren<Behaviour>(true);
			foreach (Behaviour val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null)
				{
					snap.Enabled[val] = val.enabled;
				}
			}
			if ((Object)(object)_rb != (Object)null)
			{
				snap.HasRb = true;
				snap.RbKin = _rb.isKinematic;
				snap.RbGrav = _rb.useGravity;
				snap.RbDetect = _rb.detectCollisions;
				snap.RbConstraints = _rb.constraints;
			}
			if ((Object)(object)_anim != (Object)null)
			{
				snap.HasAnim = true;
				snap.AnimOn = ((Behaviour)_anim).enabled;
				snap.AnimRoot = _anim.applyRootMotion;
				snap.AnimSpeed = _anim.speed;
			}
			return snap;
		}

		private void DiffAndRestore(bool restore)
		{
			//IL_0325: 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_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			if (_snap == null)
			{
				TameCompanionsPlugin.Log.LogInfo((object)("Zustandsvergleich: noch kein gesunder Schnappschuss vorhanden: " + ((Object)this).name));
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			int num = 0;
			foreach (FieldRef field in _snap.Fields)
			{
				object value;
				try
				{
					value = field.F.GetValue(field.Obj);
				}
				catch
				{
					continue;
				}
				if (object.Equals(value, field.Val))
				{
					continue;
				}
				Type fieldType = field.F.FieldType;
				if (fieldType == typeof(float))
				{
					continue;
				}
				if (num++ < 80)
				{
					stringBuilder.Append(field.Key).Append(": ").Append(field.Val)
						.Append("->")
						.Append(value)
						.Append(" | ");
				}
				bool flag = field.Key.IndexOf("sleep", StringComparison.OrdinalIgnoreCase) >= 0;
				if (restore && !flag && (fieldType == typeof(bool) || fieldType.IsEnum))
				{
					try
					{
						field.F.SetValue(field.Obj, field.Val);
					}
					catch
					{
					}
				}
			}
			int num2 = 0;
			foreach (KeyValuePair<Behaviour, bool> item in _snap.Enabled)
			{
				if ((Object)(object)item.Key != (Object)null && item.Value && !item.Key.enabled)
				{
					stringBuilder.Append("DISABLED:").Append(((object)item.Key).GetType().Name).Append(" | ");
					if (restore)
					{
						item.Key.enabled = true;
						num2++;
					}
				}
			}
			if ((Object)(object)_rb != (Object)null && _snap.HasRb && (_rb.isKinematic != _snap.RbKin || _rb.useGravity != _snap.RbGrav || _rb.detectCollisions != _snap.RbDetect || _rb.constraints != _snap.RbConstraints))
			{
				stringBuilder.Append("RB:").Append(_snap.RbKin).Append('/')
					.Append(_snap.RbGrav)
					.Append('/')
					.Append(_snap.RbConstraints)
					.Append("->")
					.Append(_rb.isKinematic)
					.Append('/')
					.Append(_rb.useGravity)
					.Append('/')
					.Append(_rb.constraints)
					.Append(" | ");
				if (restore)
				{
					_rb.isKinematic = _snap.RbKin;
					_rb.useGravity = _snap.RbGrav;
					_rb.detectCollisions = _snap.RbDetect;
					_rb.constraints = _snap.RbConstraints;
				}
			}
			if ((Object)(object)_anim != (Object)null && _snap.HasAnim && (((Behaviour)_anim).enabled != _snap.AnimOn || _anim.applyRootMotion != _snap.AnimRoot || Mathf.Abs(_anim.speed - _snap.AnimSpeed) > 0.01f))
			{
				stringBuilder.Append("ANIM:").Append(_snap.AnimOn).Append('/')
					.Append(_snap.AnimRoot)
					.Append('/')
					.Append(_snap.AnimSpeed)
					.Append("->")
					.Append(((Behaviour)_anim).enabled)
					.Append('/')
					.Append(_anim.applyRootMotion)
					.Append('/')
					.Append(_anim.speed)
					.Append(" | ");
				if (restore)
				{
					((Behaviour)_anim).enabled = _snap.AnimOn;
					_anim.applyRootMotion = _snap.AnimRoot;
					_anim.speed = _snap.AnimSpeed;
				}
			}
			TameCompanionsPlugin.Log.LogInfo((object)("Zustandsvergleich (" + ((Object)this).name + "): " + ((stringBuilder.Length == 0) ? "keine Unterschiede" : stringBuilder.ToString())));
		}

		private string DumpState()
		{
			StringBuilder sb = new StringBuilder();
			Action<string, Func<object>> action = delegate(string k, Func<object> f)
			{
				try
				{
					sb.Append(k).Append('=').Append(f())
						.Append(' ');
				}
				catch
				{
					sb.Append(k).Append("=? ");
				}
			};
			action("owner", () => Nv.IsOwner());
			action("downLeft", () => DownLeft);
			action("isDowned", () => IsDowned);
			action("visualDown", () => _visualDown);
			action("anim.sleeping", () => _anim.GetBool("sleeping"));
			action("hp", () => Ch.GetHealth());
			action("ai.on", () => ((Behaviour)Ai).enabled);
			action("sleeping", () => Traverse.Create((object)Ai).Field("m_sleeping").GetValue());
			action("alerted", () => ((BaseAI)Ai).IsAlerted());
			action("follow", () => (Object)(object)Ai.GetFollowTarget() != (Object)null);
			action("target", () => (Object)(object)((BaseAI)Ai).GetTargetCreature() != (Object)null);
			action("moveDir", () => Traverse.Create((object)Ch).Field("m_moveDir").GetValue());
			action("ground", () => Traverse.Create((object)Ch).Method("IsOnGround", Array.Empty<object>()).GetValue());
			action("rb.kin", () => _rb.isKinematic);
			action("rb.constr", () => _rb.constraints);
			action("rb.vel", () => _rb.velocity);
			action("rb.sleep", () => _rb.IsSleeping());
			action("rb.grav", () => _rb.useGravity);
			action("anim.on", () => ((Behaviour)_anim).enabled);
			action("anim.speed", () => _anim.speed);
			action("anim.state", delegate
			{
				//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)
				AnimatorStateInfo currentAnimatorStateInfo = _anim.GetCurrentAnimatorStateInfo(0);
				return ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash;
			});
			action("zsync", () => ((Behaviour)((Component)this).GetComponent<ZSyncTransform>()).enabled);
			action("se", delegate
			{
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				object value = Traverse.Create((object)Ch).Field("m_seman").GetValue();
				List<string> list = new List<string>();
				if (Traverse.Create(value).Field("m_statusEffects").GetValue() is IEnumerable enumerable)
				{
					foreach (object item in enumerable)
					{
						list.Add(((Object)item).name);
					}
				}
				return string.Join(",", list.ToArray());
			});
			return sb.ToString();
		}

		private bool IsLost(float dt, bool dungeon, out string why)
		{
			//IL_000a: 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_0021: 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_00be: 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_00cc: 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_00d8: 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_00f0: 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_00fa: 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_00fe: Unknown result type (might be due to invalid IL or missing references)
			why = null;
			Vector3 position = ((Component)this).transform.position;
			try
			{
				if (!dungeon && (Object)(object)ZoneSystem.instance != (Object)null && position.y < ZoneSystem.instance.GetGroundHeight(position) - 2.5f)
				{
					why = "unter dem Boden";
					return true;
				}
			}
			catch
			{
			}
			bool flag = false;
			try
			{
				if (_embedMask < 0)
				{
					_embedMask = LayerMask.GetMask(new string[2] { "piece", "static_solid" });
				}
				float num = Mathf.Max(0.25f, BodyRadius * 0.6f);
				float num2 = Mathf.Clamp(BodyRadius * 2f, 1f, 1.5f);
				Vector3 val = position + Vector3.up * (num + 0.25f);
				Vector3 val2 = position + Vector3.up * Mathf.Max(num + 0.25f, num2 - num);
				flag = Physics.CheckCapsule(val, val2, num, _embedMask, (QueryTriggerInteraction)1);
			}
			catch
			{
			}
			if (flag)
			{
				_embeddedTime += dt;
				if (_embeddedTime >= 3f)
				{
					_embeddedTime = 0f;
					why = "in Bauteil/Fels eingeklemmt";
					return true;
				}
			}
			else
			{
				_embeddedTime = 0f;
			}
			return false;
		}

		private void TeleportBehind(Player leader)
		{
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: 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_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)
			//IL_00a9: 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_0124: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: 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)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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)
			Ship val = (Cfg.ShipEnabled.Value ? ShipHelper.ShipOf(leader) : null);
			Vector3 pos;
			Quaternion rot;
			if ((Object)(object)val != (Object)null)
			{
				if (ShipHelper.Excluded(((Component)this).gameObject) || !ShipHelper.TryFindDeck(val, leader, this, out pos))
				{
					return;
				}
				Vector3 forward = ((Component)leader).transform.forward;
				forward.y = 0f;
				rot = ((((Vector3)(ref forward)).sqrMagnitude > 0.001f) ? Quaternion.LookRotation(forward) : ((Component)this).transform.rotation);
			}
			else
			{
				pos = CompanionManager.FindBehind(leader, Cfg.BehindDistance.Value, out rot, BodyRadius);
			}
			((Component)this).transform.position = pos;
			((Component)this).transform.rotation = rot;
			if ((Object)(object)_rb != (Object)null)
			{
				_rb.position = pos;
				_rb.rotation = rot;
				_rb.velocity = Vector3.zero;
				_rb.angularVelocity = Vector3.zero;
				_rb.WakeUp();
			}
			Nv.GetZDO().SetPosition(pos);
			try
			{
				((BaseAI)Ai).StopMoving();
			}
			catch
			{
			}
			try
			{
				Traverse.Create((object)Ch).Field("m_maxAirAltitude").SetValue((object)pos.y);
			}
			catch
			{
			}
			if (!((Behaviour)Ai).enabled)
			{
				((Behaviour)Ai).enabled = true;
			}
			_aiOffByUs = false;
			ForceAwake();
			((BaseAI)Ai).ResetPatrolPoint();
			Ai.SetFollowTarget(((Component)leader).gameObject);
			_lastPos = pos;
			_stuckTime = 0f;
			_softResets = 0;
			_embeddedTime = 0f;
		}

		internal bool HoldFollow(GameObject target)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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)
			if ((Object)(object)target == (Object)null || (Object)(object)Ch == (Object)null || !Ch.IsTamed())
			{
				return false;
			}
			if (Aboard)
			{
				try
				{
					((BaseAI)Ai).StopMoving();
				}
				catch
				{
				}
				return true;
			}
			Vector3 val = target.transform.position - ((Component)this).transform.position;
			val.y = 0f;
			float magnitude = ((Vector3)(ref val)).magnitude;
			float num = ((target.transform.position.y > 3000f) ? 0.6f : 1f);
			float bodyRadius = BodyRadius;
			float num2 = (Cfg.FollowStopDistance.Value + bodyRadius) * num;
			float num3 = Mathf.Max((Cfg.FollowResumeDistance.Value + bodyRadius) * num, num2 + 1.5f);
			if (_holding)
			{
				if (magnitude > num3)
				{
					_holding = false;
				}
			}
			else if (magnitude < num2)
			{
				_holding = true;
			}
			if (!_holding)
			{
				return false;
			}
			try
			{
				((BaseAI)Ai).StopMoving();
			}
			catch
			{
			}
			return true;
		}

		private void Regen(float dt, bool inCombat)
		{
			float maxHealth = Ch.GetMaxHealth();
			float health = Ch.GetHealth();
			if (!(health >= maxHealth))
			{
				float num = (inCombat ? Cfg.RegenCombatPct.Value : Cfg.RegenRestPct.Value);
				float num2 = (SafeHungry() ? Cfg.HungryMult.Value : Cfg.FedMult.Value);
				float num3 = maxHealth * (num / 100f) * num2 * dt;
				if (num3 > 0f)
				{
					Ch.SetHealth(Mathf.Min(maxHealth, health + num3));
				}
			}
		}

		internal void EnterDowned()
		{
			ZDO zDO = Nv.GetZDO();
			if (zDO.GetFloat("TC_DownLeft", 0f) > 0f)
			{
				Ch.SetHealth(1f);
				return;
			}
			long num = zDO.GetLong("TC_RecStamp", 0L);
			TameCompanionsPlugin.Log.LogInfo((object)("Bewusstlos: " + ((Object)this).name + " | " + ((num == 0L) ? "erstmals" : (((float)(NowMs() - num) / 1000f).ToString("0.0") + " s nach letzter Erholung")) + " | " + DumpState()));
			int num2 = Mathf.Max(0, Ch.GetLevel() - 1);
			float num3 = Mathf.Max(0.3f, 1f - Cfg.DownedStarReduction.Value * (float)num2);
			float num4 = Cfg.DownedSeconds.Value * num3;
			zDO.Set("TC_DownLeft", num4);
			zDO.Set("TC_DownStamp", NowMs());
			Ch.SetHealth(1f);
			CompanionManager.SetAlerted(Ai, alerted: false);
			try
			{
				Ai.SetFollowTarget((GameObject)null);
			}
			catch
			{
			}
			SetAiActive(on: false);
			_visualDown = false;
			ApplyDownVisual(down: true);
			_stuckTime = 0f;
			_softResets = 0;
			CompanionManager.Say(((Component)this).gameObject, Loc.T("down_say"));
		}

		private bool DownedWillEnd()
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = Nv.GetZDO();
			if (zDO == null || (Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			float num = zDO.GetFloat("TC_DownLeft", 0f);
			if (num <= 0f)
			{
				return false;
			}
			long num2 = NowMs();
			float num3 = Mathf.Max(0f, (float)(num2 - zDO.GetLong("TC_DownStamp", num2)) / 1000f);
			float num4 = Mathf.Min(num3, 1.5f);
			float num5 = (((Object)(object)Player.GetClosestPlayer(((Component)this).transform.position, 15f) != (Object)null) ? Cfg.LeaderNearSpeed.Value : 1f);
			return num - (num3 - num4 + num4 * num5) <= 0f;
		}

		private bool TickDowned(float dt)
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: 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)
			ZDO zDO = Nv.GetZDO();
			float num = zDO.GetFloat("TC_DownLeft", 0f);
			if (num <= 0f)
			{
				if (_aiOffByUs)
				{
					WakeUp();
				}
				return false;
			}
			if (!Cfg.TamesProtected())
			{
				Recover();
				return true;
			}
			long num2 = NowMs();
			long num3 = zDO.GetLong("TC_DownStamp", num2);
			float num4 = Mathf.Max(0f, (float)(num2 - num3) / 1000f);
			float num5 = Mathf.Min(num4, 1.5f);
			float num6 = num4 - num5;
			float num7 = (((Object)(object)Player.GetClosestPlayer(((Component)this).transform.position, 15f) != (Object)null) ? Cfg.LeaderNearSpeed.Value : 1f);
			num -= num6 + num5 * num7;
			zDO.Set("TC_DownStamp", num2);
			if (num <= 0f)
			{
				Recover();
				return true;
			}
			zDO.Set("TC_DownLeft", num);
			SetAiActive(on: false);
			if (Ch.GetHealth() < 1f)
			{
				Ch.SetHealth(1f);
			}
			if ((Object)(object)_rb != (Object)null)
			{
				_rb.velocity = new Vector3(0f, _rb.velocity.y, 0f);
			}
			return true;
		}

		private void Recover()
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			ZDO zDO = Nv.GetZDO();
			zDO.Set("TC_DownLeft", 0f);
			zDO.Set("TC_RecStamp", NowMs());
			ClearStatusEffects();
			Ch.SetHealth(Ch.GetMaxHealth() * Cfg.RecoverHealthPct.Value / 100f);
			_lastHp = Ch.GetHealth();
			WakeUp();
			Player val = FindPlayer(zDO.GetLong("TC_Leader", 0L));
			if ((Object)(object)val != (Object)null && !((Character)val).IsDead())
			{
				try
				{
					((BaseAI)Ai).ResetPatrolPoint();
					Ai.SetFollowTarget(((Component)val).gameObject);
				}
				catch
				{
				}
			}
			_lastPos = ((Component)this).transform.position;
			_stuckTime = 0f;
			_softResets = 0;
			_recoverCheckUntil = Time.time + 20f;
			_standUntil = Time.time + 4f;
			_recoverAt = Time.time;
			_recoverPos = ((Component)this).transform.position;
			_rebindDone = false;
			_lockUntil = Mathf.Max(_lockUntil, Time.time + Mathf.Max(0f, Cfg.RecoverLockSeconds.Value));
			if (Cfg.DebugLog.Value)
			{
				string text = "?";
				try
				{
					text = Convert.ToString(Traverse.Create((object)Ai).Field("m_sleeping").GetValue());
				}
				catch
				{
				}
				TameCompanionsPlugin.Log.LogInfo((object)string.Format("Recover {0}: ai.enabled={1} m_sleeping={2} follow={3} leader={4}", ((Object)this).name, ((Behaviour)Ai).enabled, text, (Object)(object)Ai.GetFollowTarget() != (Object)null, ((Object)(object)val != (Object)null) ? val.GetPlayerName() : "none"));
			}
			CompanionManager.Say(((Component)this).gameObject, Loc.T("up_say"));
		}

		private void WakeUp()
		{
			//IL_0043: 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)
			SetAiActive(on: true);
			_visualDown = false;
			ForceAwake();
			ResetAnimator(skipGetUp: true);
			if ((Object)(object)_rb != (Object)null)
			{
				_rb.isKinematic = false;
				_rb.velocity = Vector3.zero;
				_rb.angularVelocity = Vector3.zero;
				_rb.WakeUp();
			}
		}

		private void SetAiActive(bool on)
		{
			if (!on)
			{
				try
				{
					((BaseAI)Ai).StopMoving();
				}
				catch
				{
				}
			}
			((Behaviour)Ai).enabled = on;
			_aiOffByUs = !on;
		}

		private void ForceAwake()
		{
			try
			{
				WakeupMethod?.Invoke(Ai, null);
			}
			catch
			{
			}
			try
			{
				Traverse.Create((object)Ai).Field("m_sleeping").SetValue((object)false);
			}
			catch
			{
			}
			try
			{
				Nv.GetZDO().Set("sleeping", false);
			}
			catch
			{
			}
		}

		private bool IsStillLying()
		{
			if (_visualDown)
			{
				return true;
			}
			if (HasSleepParam() && (Object)(object)_anim != (Object)null && _anim.GetBool("sleeping"))
			{
				return true;
			}
			try
			{
				if (SleepingField != null && (bool)SleepingField.GetValue(Ai))
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private void SetSleepAnim(bool on)
		{
			if ((Object)(object)_anim == (Object)null || !HasSleepParam())
			{
				return;
			}
			try
			{
				if ((Object)(object)Nv != (Object)null && Nv.IsOwner() && (Object)(object)_zanim != (Object)null)
				{
					_zanim.SetBool("sleeping", on);
				}
				_anim.SetBool("sleeping", on);
			}
			catch
			{
			}
		}

		private void LateUpdate()
		{
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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)
			if (!_inited || _standUntil <= 0f || (Object)(object)Nv == (Object)null || !Nv.IsValid() || !Nv.IsOwner() || IsDowned)
			{
				return;
			}
			if (Time.time >= _standUntil)
			{
				_standUntil = 0f;
				if (_recoverAt >= 0f)
				{
					TameCompanionsPlugin.Log.LogInfo((object)("Keine Bewegung in 4 s nach Erholung: " + ((Object)this).name + " | " + DumpState()));
					_recoverAt = -1f;
				}
				try
				{
					if (IsStillLying())
					{
						TameCompanionsPlugin.Log.LogWarning((object)("Tame liegt nach Erholung noch: " + ((Object)this).name + " | " + DumpState()));
					}
					return;
				}
				catch
				{
					return;
				}
			}
			try
			{
				if (_recoverAt >= 0f)
				{
					Vector3 val = ((Component)this).transform.position - _recoverPos;
					if (((Vector3)(ref val)).sqrMagnitude > 0.25f)
					{
						TameCompanionsPlugin.Log.LogInfo((object)("Erste Bewegung " + (Time.time - _recoverAt).ToString("0.00") + " s nach Erholung: " + ((Object)this).name));
						_recoverAt = -1f;
					}
				}
				if (!((Behaviour)Ai).enabled)
				{
					((Behaviour)Ai).enabled = true;
				}
				_aiOffByUs = false;
				if (SleepingField != null && (bool)SleepingField.GetValue(Ai))
				{
					SleepingField.SetValue(Ai, false);
				}
				if (HasSleepParam() && (Object)(object)_anim != (Object)null && _anim.GetBool("sleeping"))
				{
					SetSleepAnim(on: false);
				}
				if (ParamExists("dead"))
				{
					_anim.ResetTrigger("dead");
				}
			}
			catch
			{
			}
		}

		private bool ParamExists(string name)
		{
			if (_paramCache.TryGetValue(name, out var value))
			{
				return value;
			}
			value = false;
			if ((Object)(object)_anim != (Object)null)
			{
				try
				{
					AnimatorControllerParameter[] parameters = _anim.parameters;
					foreach (AnimatorControllerParameter val in parameters)
					{
						if (val.name == name)
						{
							value = true;
							break;
						}
					}
				}
				catch
				{
				}
			}
			_paramCache[name] = value;
			return value;
		}

		private bool HasSleepParam()
		{
			return ParamExists("sleeping");
		}

		private void ApplyDownVisual(bool down)
		{
			if (_visualDown == down || (Object)(object)_anim == (Object)null)
			{
				return;
			}
			_visualDown = down;
			try
			{
				if (down)
				{
					if (HasSleepParam())
					{
						if (Nv.IsOwner())
						{
							if ((Object)(object)_zanim != (Object)null)
							{
								_zanim.SetBool("sleeping", true);
							}
							_anim.SetBool("sleeping", true);
						}
					}
					else if (ParamExists("dead"))
					{
						_anim.SetTrigger("dead");
					}
				}
				else
				{
					ResetAnimator();
				}
			}
			catch
			{
			}
		}

		private void ResetAnimator(bool skipGetUp = false)
		{
			try
			{
				if ((Object)(object)Nv != (Object)null && Nv.IsOwner() && (Object)(object)_zanim != (Object)null && HasSleepParam())
				{
					_zanim.SetBool("sleeping", false);
				}
				if ((Object)(object)_anim != (Object)null)
				{
					_anim.Rebind();
					_anim.Update(0f);
					if (skipGetUp)
					{
						_anim.Update(2f);
					}
				}
			}
			catch
			{
			}
		}

		private void RPC_Butcher(long sender)
		{
			_butcherUntil = Time.time + 2f;
		}

		internal void NotifyButcher()
		{
			if (_inited && (Object)(object)Nv != (Object)null && Nv.IsValid())
			{
				Nv.InvokeRPC("TC_Butcher", Array.Empty<object>());
			}
		}

		private void RPC_Help(long sender, float seconds)
		{
			if (!Nv.IsOwner())
			{
				return;
			}
			ZDO zDO = Nv.GetZDO();
			float num = zDO.GetFloat("TC_DownLeft", 0f);
			if (!(num <= 0f))
			{
				num -= seconds;
				if (num <= 0.5f)
				{
					Recover();
				}
				else
				{
					zDO.Set("TC_DownLeft", num);
				}
			}
		}

		internal void Help()
		{
			if (IsDowned)
			{
				_lockUntil = Time.time + Mathf.Max(0f, Cfg.RecoverLockSeconds.Value);
			}
			Nv.InvokeRPC("TC_Help", new object[1] { Cfg.HelpSeconds.Value });
		}

		internal void GiveXp(float xp)
		{
			if (xp > 0f && _inited && (Object)(object)Nv != (Object)null && Nv.IsValid())
			{
				Nv.InvokeRPC("TC_AddXp", new object[1] { xp });
			}
		}

		private void RPC_AddXp(long sender, float xp)
		{
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: 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)
			if (!Nv.IsOwner() || !Ch.IsTamed() || !Cfg.StarsEnabled.Value || xp <= 0f)
			{
				return;
			}
			ZDO zDO = Nv.GetZDO();
			float num = zDO.GetFloat("TC_Xp", 0f) + xp;
			zDO.Set("TC_Xp", num);
			float value = Cfg.XpStar1.Value;
			float num2 = Mathf.Max(value, Cfg.XpStar2.Value);
			int num3 = ((num >= num2) ? 2 : ((num >= value) ? 1 : 0));
			num3 = Mathf.Min(num3, Cfg.MaxStars.Value);
			int num4 = Ch.GetLevel() - 1;
			if (num3 <= num4)
			{
				return;
			}
			Ch.SetLevel(num3 + 1);
			zDO.Set("TC_Level", num3 + 1);
			Ch.SetHealth(Ch.GetMaxHealth());
			try
			{
				EffectList tamedEffect = Tm.m_tamedEffect;
				if (tamedEffect != null)
				{
					tamedEffect.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1, default(ZDOID));
				}
			}
			catch
			{
			}
			CompanionManager.Say(((Component)this).gameObject, Loc.T("star_up", num3, Cfg.MaxStars.Value));
		}

		private void SyncLevelVisual()
		{
			ZDO zDO = Nv.GetZDO();
			if (zDO != null)
			{
				int num = zDO.GetInt("TC_Level", 0);
				if (num > 0 && num != Ch.GetLevel())
				{
					Ch.SetLevel(num);
				}
			}
		}

		internal static string Fmt(float sec)
		{
			int num = Mathf.Max(0, Mathf.CeilToInt(sec));
			return num / 60 + ":" + (num % 60).ToString("00");
		}

		internal string HudLabel()
		{
			if ((Object)(object)Nv == (Object)null || !Nv.IsValid() || (Object)(object)Ch == (Object)null || !Ch.IsTamed())
			{
				return "";
			}
			if (IsDowned)
			{
				return "<color=#ff5a5a>" + Loc.T("knocked") + " " + Fmt(DownLeft) + "</color>";
			}
			long leaderId = LeaderId;
			if (leaderId == 0)
			{
				return "";
			}
			Player val = FindPlayer(leaderId);
			if ((Object)(object)val == (Object)null)
			{
				return "";
			}
			return "<color=#ffffff>" + Loc.T("follows", val.GetPlayerName()) + "</color>";
		}

		internal string ExtraHover()
		{
			if ((Object)(object)Nv == (Object)null)
			{
				return "";
			}
			ZDO zDO = Nv.GetZDO();
			if (zDO == null)
			{
				return "";
			}
			if (!Ch.IsTamed())
			{
				if (!Cfg.ShowTimer.Value)
				{
					return "";
				}
				float tamingTime = Tm.m_tamingTime;
				if (tamingTime <= 0f)
				{
					return "";
				}
				float num = zDO.GetFloat("TameTimeLeft", tamingTime);
				if (!(num < tamingTime - 0.5f))
				{
					return "";
				}
				float num2 = Mathf.Clamp01(1f - num / tamingTime) * 100f;
				string text = "\n" + Loc.T("taming") + ": <color=yellow>" + Fmt(num) + "</color> / " + Fmt(tamingTime) + "  (" + num2.ToString("0") + "%)";
				if (SafeHungry())
				{
					text = text + "\n<color=orange>" + Loc.T("paused") + "</color>";
				}
				return text;
			}
			string text2 = "";
			if (IsDowned)
			{
				text2 = text2 + "\n<color=red>" + Loc.T("knocked") + ": " + Fmt(DownLeft) + "</color>  " + CompanionManager.WrapHint(CompanionManager.UseKeyHint()) + Loc.T("first_aid");
			}
			else if (Tm.m_commandable && Cfg.ShowGroupKeyHint.Value)
			{
				text2 = text2 + "\n" + CompanionManager.WrapHint(CompanionManager.GroupKeyHint()) + Loc.T("all_cmd");
			}
			return text2;
		}
	}
	internal static class CompanionManager
	{
		internal const string RecallRpc = "TC_Recall";

		internal static bool PlayerDied;

		internal static float LastGroupCommand;

		private static int _mask = -1;

		private static readonly MethodInfo TakeInputMethod = AccessTools.Method(typeof(Player), "TakeInput", (Type[])null, (Type[])null);

		private static readonly MethodInfo SetAlertedMethod = AccessTools.Method(typeof(BaseAI), "SetAlerted", (Type[])null, (Type[])null);

		private static readonly HashSet<string> GlyphLogged = new HashSet<string>();

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

		internal static void Say(GameObject go, string text)
		{
			//IL_0058: 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)
			try
			{
				if (!((Object)(object)Chat.instance == (Object)null) && !((Object)(object)go == (Object)null))
				{
					MethodInfo methodInfo = AccessTools.Method(typeof(Chat), "SetNpcText", (Type[])null, (Type[])null);
					if (!(methodInfo == null))
					{
						methodInfo.Invoke(Chat.instance, new object[7]
						{
							go,
							Vector3.up * 2f,
							25f,
							4f,
							"",
							text,
							false
						});
					}
				}
			}
			catch
			{
			}
		}

		internal static bool CanTakeInput(Player p)
		{
			try
			{
				return TakeInputMethod == null || (bool)TakeInputMethod.Invoke(p, null);
			}
			catch
			{
				return true;
			}
		}

		internal static void SetAlerted(MonsterAI ai, bool alerted)
		{
			try
			{
				if (SetAlertedMethod != null)
				{
					SetAlertedMethod.Invoke(ai, new object[1] { alerted });
				}
			}
			catch
			{
			}
		}

		internal static bool IsButcherKnife(ItemData w)
		{
			if (w == null || w.m_shared == null)
			{
				return false;
			}
			if (w.m_shared.m_name == "$item_knife_butcher")
			{
				return true;
			}
			return (Object)(object)w.m_dropPrefab != (Object)null && ((Object)w.m_dropPrefab).name == "KnifeButcher";
		}

		private static string CleanName(string n)
		{
			return (n ?? "").Replace("(Clone)", "").Trim();
		}

		internal static bool IsExcludedName(string prefabName)
		{
			string text = CleanName(prefabName);
			if (text.Length == 0)
			{
				return false;
			}
			string[] array = Cfg.DungeonExcluded.Value.Split(new char[1] { ',' });
			foreach (string text2 in array)
			{
				if (string.Equals(text2.Trim(), text, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		internal static bool IsDungeonExcluded(GameObject go)
		{
			return IsExcludedName(((Object)go).name);
		}

		private static List<CompanionController> Nearby(Player p)
		{
			//IL_000e: 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)
			Vector3 pos = ((Component)p).transform.position;
			float r = Cfg.CommandRadius.Value;
			return CompanionController.All.Where((CompanionController c) => (Object)(object)c != (Object)null && (Object)(object)c.Nv != (Object)null && c.Nv.IsValid() && c.Ch.IsTamed() && c.Tm.m_commandable && !c.IsDowned && !c.ActionLocked && Vector3.Distance(((Component)c).transform.position, pos) <= r).ToList();
		}

		private static void ApplyAll(Player p, List<CompanionController> list, bool follow)
		{
			foreach (CompanionController item in list)
			{
				item.SetFollow(p, follow);
			}
			try
			{
				((MonoBehaviour)TameCompanionsPlugin.Instance).StartCoroutine(PetEffects(list));
			}
			catch
			{
			}
			((Character)p).Message((MessageType)2, follow ? Loc.T("follow_n", list.Count) : Loc.T("stay_n", list.Count), 0, (Sprite)null, false);
		}

		internal static void PlayPet(CompanionController c)
		{
			//IL_0041: 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_005a: 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)
			try
			{
				if (!((Object)(object)c == (Object)null) && !((Object)(object)c.Tm == (Object)null) && c.Tm.m_petEffect != null)
				{
					c.Tm.m_petEffect.Create(((Component)c).transform.position, ((Component)c).transform.rotation, (Transform)null, 1f, -1, default(ZDOID));
				}
			}
			catch
			{
			}
		}

		private static IEnumerator PetEffects(List<CompanionController> list)
		{
			float gap = Mathf.Clamp(1.2f / (float)Mathf.Max(1, list.Count), 0.04f, 0.2f);
			for (int i = 0; i < list.Count; i++)
			{
				PlayPet(list[i]);
				if (i < list.Count - 1)
				{
					yield return (object)new WaitForSeconds(Random.Range(gap * 0.5f, gap));
				}
			}
		}

		internal static void ToggleAll(Player p)
		{
			if (Time.time - LastGroupCommand < 0.6f)
			{
				return;
			}
			LastGroupCommand = Time.time;
			List<CompanionController> list = Nearby(p);
			if (list.Count == 0)
			{
				((Character)p).Message((MessageType)2, Loc.T("none"), 0, (Sprite)null, false);
				return;
			}
			bool flag = list.Any((CompanionController c) => c.FollowsPlayer(p));
			ApplyAll(p, list, !flag);
		}

		internal static int CountFollowers(Player p)
		{
			long playerID = p.GetPlayerID();
			int num = 0;
			foreach (CompanionController item in CompanionController.All)
			{
				if (!((Object)(object)item == (Object)null) && !((Object)(object)item.Nv == (Object)null) && item.Nv.IsValid() && !((Object)(object)item.Ch == (Object)null) && item.Ch.IsTamed() && item.LeaderId == playerID)
				{
					num++;
				}
			}
			return num;
		}

		internal static void ToggleSingle(CompanionController c, Player p)
		{
			if (!c.IsDowned && !c.ActionLocked && !(Time.time - c.LastToggle < 1f))
			{
				c.LastToggle = Time.time;
				bool flag = c.LeaderId != 0L || (c.Nv.IsOwner() && (Object)(object)c.Ai.GetFollowTarget() != (Object)null);
				c.SetFollow(p, !flag);
				PlayPet(c);
				((Character)p).Message((MessageType)2, SingleMessage(c, !flag), 0, (Sprite)null, false);
				if (Cfg.DebugLog.Value)
				{
					TameCompanionsPlugin.Log.LogInfo((object)$"ToggleSingle {((Object)c).name}: follow={!flag}");
				}
			}
		}

		private static string SingleMessage(CompanionController c, bool follow)
		{
			string text = c.Ch.m_name;
			string text2 = null;
			try
			{
				if (Localization.instance != null)
				{
					string hoverName = c.Ch.GetHoverName();
					text = Localization.instance.Localize(string.IsNullOrEmpty(hoverName) ? c.Ch.m_name : hoverName);
					text2 = Localization.instance.Localize(follow ? "$hud_tamefollow" : "$hud_tamestay");
					if (string.IsNullOrEmpty(text2) || text2.StartsWith("[") || text2.Contains("$"))
					{
						text2 = null;
					}
				}
			}
			catch
			{
				text2 = null;
			}
			if (text2 == null)
			{
				text2 = Loc.T(follow ? "tame_follow" : "tame_stay");
			}
			return text + " " + text2;
		}

		private unsafe static string PadName(GamepadButton b)
		{
			return ((object)(*(GamepadButton*)(&b))/*cast due to .constrained prefix*/).ToString() switch
			{
				"RightStickButton" => "R3", 
				"LeftStickButton" => "L3", 
				"LeftTrigger" => "L2/LT", 
				"RightTrigger" => "R2/RT", 
				"LeftShoulder" => "L1/LB", 
				"RightShoulder" => "R1/RB", 
				"ButtonSouth" => "✕/A", 
				"ButtonEast" => "○/B", 
				"ButtonWest" => "□/X", 
				"ButtonNorth" => "△/Y", 
				"DPadUp" => "D-Pad ↑", 
				"DPadDown" => "D-Pad ↓", 
				"DPadLeft" => "D-Pad ←", 
				"DPadRight" => "D-Pad →", 
				_ => ((object)(*(GamepadButton*)(&b))/*cast due to .constrained prefix*/).ToString(), 
			};
		}

		internal static string UseKeyHint()
		{
			bool flag = false;
			try
			{
				flag = ZInput.IsGamepadActive();
			}
			catch
			{
			}
			try
			{
				if (Localization.instance != null)
				{
					string text = Localization.instance.Localize("$KEY_Use");
					if (IsValidKeyText(text))
					{
						return text;
					}
				}
			}
			catch
			{
			}
			return flag ? PadName((GamepadButton)5) : "E";
		}

		private static bool IsValidKeyText(string k)
		{
			if (string.IsNullOrEmpty(k))
			{
				return false;
			}
			if (k.Contains("$") || k.StartsWith("["))
			{
				return false;
			}
			if (k.IndexOf("MISSING", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return false;
			}
			if (k.IndexOf("BUTTON DEF", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return false;
			}
			if (k.Contains("TC_Hint"))
			{
				return false;
			}
			return true;
		}

		private static string[] VanillaPadNames(string b)
		{
			return b switch
			{
				"ButtonSouth" => new string[1] { "JoyButtonA" }, 
				"ButtonEast" => new string[1] { "JoyButtonB" }, 
				"ButtonWest" => new string[1] { "JoyButtonX" }, 
				"ButtonNorth" => new string[1] { "JoyButtonY" }, 
				"LeftShoulder" => new string[1] { "JoyLBumper" }, 
				"RightShoulder" => new string[1] { "JoyRBumper" }, 
				"LeftTrigger" => new string[1] { "JoyLTrigger" }, 
				"RightTrigger" => new string[1] { "JoyRTrigger" }, 
				"LeftStickButton" => new string[1] { "JoyLStick" }, 
				"RightStickButton" => new string[1] { "JoyRStick" }, 
				"Start" => new string[1] { "JoyStart" }, 
				"Select" => new string[1] { "JoyBack" }, 
				"DPadUp" => new string[1] { "JoyDPadUp" }, 
				"DPadDown" => new string[1] { "JoyDPadDown" }, 
				"DPadLeft" => new string[1] { "JoyDPadLeft" }, 
				"DPadRight" => new string[1] { "JoyDPadRight" }, 
				_ => new string[0], 
			};
		}

		private static bool IsGlyph(string g)
		{
			return IsValidKeyText(g) && g.IndexOf("<sprite", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static string LocalizeKey(string name)
		{
			try
			{
				if (Localization.instance != null)
				{
					return Localization.instance.Localize("$KEY_" + name);
				}
			}
			catch
			{
			}
			return null;
		}

		private unsafe static string TryPadGlyph(string hintName, GamepadButton btn)
		{
			List<string> list = new List<string> { hintName };
			list.AddRange(VanillaPadNames(((object)(*(GamepadButton*)(&btn))/*cast due to .constrained prefix*/).ToString()));
			string result = null;
			foreach (string item in list)
			{
				string text = LocalizeKey(item);
				if (Cfg.DebugLog.Value && GlyphLogged.Add(item + "|" + text))
				{
					TameCompanionsPlugin.Log.LogInfo((object)$"Glyph-Test $KEY_{item} -> '{text}' (Symbol={IsGlyph(text)})");
				}
				if (IsGlyph(text))
				{
					result = text;
					break;
				}
			}
			return result;
		}

		internal static string GroupKeyHint()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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)
			//IL_0026: 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_00c1: 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)
			bool flag = false;
			try
			{
				flag = ZInput.IsGamepadActive();
			}
			catch
			{
			}
			if (!flag)
			{
				return ((object)Cfg.CommandAllKey.Value/*cast due to .constrained prefix*/).ToString();
			}
			bool flag2 = ((object)Cfg.CommandAllPadModifier.Value/*cast due to .constrained prefix*/).ToString() != "None";
			string text = TryPadGlyph("TC_HintMain", Cfg.CommandAllPad.Value);
			string text2 = (flag2 ? TryPadGlyph("TC_HintMod", Cfg.CommandAllPadModifier.Value) : null);
			if (text != null && (!flag2 || text2 != null))
			{
				return flag2 ? (text2 + " + " + text) : text;
			}
			string text3 = PadName(Cfg.CommandAllPad.Value);
			return flag2 ? (PadName(Cfg.CommandAllPadModifier.Value) + " + " + text3) : text3;
		}

		internal static string WrapHint(string hint)
		{
			if (hint != null && hint.Contains("<sprite"))
			{
				return hint + " ";
			}
			return "[<color=yellow><b>" + hint + "</b></color>] ";
		}

		internal static bool IsFreeSpot(Vector3 feet, float radius)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_0049: 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_0068: 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)
			try
			{
				float num = Mathf.Clamp(radius * 0.8f, 0.25f, 1.5f);
				float num2 = Mathf.Clamp(radius * 2f, 1f, 1.8f);
				Vector3 val = feet + Vector3.up * (num + 0.2f);
				Vector3 val2 = feet + Vector3.up * Mathf.Max(num + 0.2f, num2 - num);
				return !Physics.CheckCapsule(val, val2, num, Mask, (QueryTriggerInteraction)1);
			}
			catch
			{
				return true;
			}
		}

		internal static Vector3 FindBehind(Player leader, float dist, out Quaternion rot, float radius = 0.5f)
		{
			//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_0013: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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_0077: 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_0082: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: 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_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: 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_00bd: 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_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_00cf: 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_0374: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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_00fe: 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_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: 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_0162: 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_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: 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_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: 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_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: 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_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: 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_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: 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)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)leader).transform.position;
			Vector3 forward = ((Component)leader).transform.forward;
			forward.y = 0f;
			if (((Vector3)(ref forward)).sqrMagnitude < 0.001f)
			{
				forward = Vector3.forward;
			}
			((Vector3)(ref forward)).Normalize();
			rot = Quaternion.LookRotation(forward);
			float[] array = new float[4] { 1f, 0.7f, 1.5f, 2.2f };
			float[] array2 = new float[7] { 0f, 25f, -25f, 50f, -50f, 75f, -75f };
			Vector3 val = position + Vector3.up * 1.2f;
			float[] array3 = array;
			Vector3 val4 = default(Vector3);
			RaycastHit val5 = default(RaycastHit);
			foreach (float num in array3)
			{
				float[] array4 = array2;
				foreach (float num2 in array4)
				{
					Vector3 val2 = Quaternion.AngleAxis(num2, Vector3.up) * -forward;
					if (Vector3.Dot(val2, forward) > -0.2f)
					{
						continue;
					}
					Vector3 val3 = position + val2 * (dist * num);
					((Vector3)(ref val4))..ctor(val3.x, position.y + 1.5f, val3.z);
					if (Physics.Raycast(val4, Vector3.down, ref val5, 6f, Mask) && !(((RaycastHit)(ref val5)).normal.y < 0.6f))
					{
						Vector3 val6 = ((RaycastHit)(ref val5)).point + Vector3.up * 0.15f;
						if (!Physics.Linecast(val, val6 + Vector3.up * 1f, Mask) && IsFreeSpot(val6, radius))
						{
							return val6;
						}
					}
				}
			}
			Vector3 val7 = position - forward * 1.5f + Vector3.up * 0.2f;
			if (IsFreeSpot(val7, radius))
			{
				return val7;
			}
			float[] array5 = new float[3] { 1.2f, 2f, 2.8f };
			RaycastHit val10 = default(RaycastHit);
			for (int k = 0; k < array5.Length; k++)
			{
				for (int l = 0; l < 8; l++)
				{
					Vector3 val8 = Quaternion.AngleAxis((float)l * 45f, Vector3.up) * -forward;
					Vector3 val9 = position + val8 * array5[k];
					if (Physics.Raycast(new Vector3(val9.x, position.y + 1.5f, val9.z), Vector3.down, ref val10, 4f, Mask) && !(((RaycastHit)(ref val10)).normal.y < 0.6f))
					{
						Vector3 val11 = ((RaycastHit)(ref val10)).point + Vector3.up * 0.15f;
						if (!Physics.Linecast(val, val11 + Vector3.up * 1f, Mask) && IsFreeSpot(val11, radius))
						{
							return val11;
						}
					}
				}
			}
			return position + Vector3.up * 0.3f;
		}

		internal static IEnumerator RecallAfterTeleport(Player p)
		{
			yield return null;
			yield return null;
			float t = 0f;
			while ((Object)(object)p != (Object)null && ((Character)p).IsTeleporting() && t < 40f)
			{
				t += Time.deltaTime;
				yield return null;
			}
			yield return (object)new WaitForSeconds(1f);
			if ((Object)(object)p != (Object)null && (Object)(object)p == (Object)(object)Player.m_localPlayer)
			{
				SendRecall(p);
			}
		}

		internal static IEnumerator RecallAfterRespawn(Player p)
		{
			yield return (object)new WaitForSeconds(3f);
			if ((Object)(object)p != (Object)null && (Object)(object)p == (Object)(object)Player.m_localPlayer)
			{
				SendRecall(p);
			}
		}

		internal static void SendRecall(Player p)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ZRoutedRpc instance = ZRoutedRpc.instance;
				if (instance != null)
				{
					instance.InvokeRoutedRPC(0L, "TC_Recall", new object[2]
					{
						p.GetPlayerID(),
						((Component)p).transform.position
					});
				}
			}
			catch (Exception ex)
			{
				TameCompanionsPlugin.Log.LogWarning((object)("Recall-Fehler: " + ex.Message));
			}
		}

		internal static void RPC_Recall(long sender, long leaderId, Vector3 pos)
		{
			//IL_008a: 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_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZDOMan.instance == null || !Cfg.Enabled.Value)
				{
					return;
				}
				FieldInfo fieldInfo = AccessTools.Field(typeof(ZDOMan), "m_objectsByID");
				IDictionary dictionary = ((fieldInfo != null) ? (fieldInfo.GetValue(ZDOMan.instance) as IDictionary) : null);
				if (dictionary == null)
				{
					return;
				}
				bool flag = pos.y > 3000f;
				List<ZDO> list = new List<ZDO>(dictionary.Count);
				foreach (object value in dictionary.Values)
				{
					ZDO val = (ZDO)((value is ZDO) ? value : null);
					if (val != null)
					{
						list.Add(val);
					}
				}
				int num = 0;
				foreach (ZDO item in list)
				{
					if (item.GetLong(CompanionController.H_Leader, 0L) != leaderId || Vector3.Distance(item.GetPosition(), pos) < Cfg.NoTeleportNear.Value)
					{
						continue;
					}
					if (flag)
					{
						if (!Cfg.FollowDungeons.Value)
						{
							continue;
						}
						GameObject val2 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(item.GetPrefab()) : null);
						if ((Object)(object)val2 != (Object)null && IsExcludedName(((Object)val2).name))
						{
							continue;
						}
					}
					item.SetOwner(ZDOMan.GetSessionID());
					item.Set("TC_Snap", true);
					item.SetPosition(pos + Vector3.up * 0.5f);
					item.SetOwner(0L);
					num++;
				}
				if (num > 0)
				{
					TameCompanionsPlugin.Log.LogInfo((object)$"Recall: {num} Tame(s) zu Spieler {leaderId} verschoben.");
				}
			}
			catch (Exception ex)
			{
				TameCompanionsPlugin.Log.LogWarning((object)("RPC_Recall: " + ex));
			}
		}

		internal static void AwardKill(Character victim, Character attacker)
		{
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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)
			if (!Cfg.StarsEnabled.Value || Cfg.MaxStars.Value <= 0 || (Object)(object)victim == (Object)null || (Object)(object)attacker == (Object)null || victim.IsTamed() || victim.IsPlayer())
			{
				return;
			}
			float maxHealth = victim.GetMaxHealth();
			if (maxHealth < Cfg.MinVictimHp.Value)
			{
				return;
			}
			float num = maxHealth * (1f + 0.3f * (float)(victim.GetLevel() - 1)) * (victim.IsBoss() ? 2f : 1f) * Cfg.XpMult.Value;
			CompanionController value = null;
			long num2 = 0L;
			if (attacker.IsTamed() && CompanionController.ByCharacter.TryGetValue(attacker, out value))
			{
				value.GiveXp(num);
				num2 = value.LeaderId;
			}
			else
			{
				Player val = (Player)(object)((attacker is Player) ? attacker : null);
				if (val != null)
				{
					num2 = val.GetPlayerID();
				}
			}
			if (num2 == 0)
			{
				return;
			}
			Vector3 position = ((Component)victim).transform.position;
			foreach (CompanionController item in CompanionController.All.ToList())
			{
				if (!((Object)(object)item == (Object)null) && !((Object)(object)item == (Object)(object)value) && item.Ch.IsTamed() && item.LeaderId == num2 && !(Vector3.Distance(((Component)item).transform.position, position) > Cfg.XpShareRadius.Value))
				{
					item.GiveXp(num * Cfg.XpShare.Value);
				}
			}
		}
	}
	internal static class ShipHelper
	{
		private static readonly MethodInfo GetLocalShip = AccessTools.Method(typeof(Ship), "GetLocalShip", (Type[])null, (Type[])null);

		private static readonly RaycastHit[] Hits = (RaycastHit[])(object)new RaycastHit[32];

		private static long _cId;

		private static float _cTime = -1f;

		private static Ship _cShip;

		private static Ship ShipBelow(Vector3 pos, float maxDown)
		{
			//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_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_0016: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.RaycastNonAlloc(pos + Vector3.up * 0.6f, Vector3.down, Hits, maxDown + 0.6f, -5, (QueryTriggerInteraction)1);
			for (int i = 0; i < num; i++)
			{
				if (!((Object)(object)((RaycastHit)(ref Hits[i])).collider == (Object)null))
				{
					Ship componentInParent = ((Component)((RaycastHit)(ref Hits[i])).collider).GetComponentInParent<Ship>();
					if ((Object)(object)componentInParent != (Object)null)
					{
						return componentInParent;
					}
				}
			}
			return null;
		}

		internal static Ship ShipOf(Player p)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)p == (Object)null)
			{
				return null;
			}
			long playerID = p.GetPlayerID();
			if (playerID == _cId && Time.time - _cTime < 0.25f)
			{
				return _cShip;
			}
			Ship val = null;
			try
			{
				val = ((Character)p).GetStandingOnShip();
				if ((Object)(object)val == (Object)null && (Object)(object)p == (Object)(object)Player.m_localPlayer && GetLocalShip != null)
				{
					object? obj = GetLocalShip.Invoke(null, null);
					val = (Ship)((obj is Ship) ? obj : null);
				}
				if ((Object)(object)val == (Object)null)
				{
					val = ShipBelow(((Component)p).transform.position, 2f);
				}
			}
			catch
			{
				val = null;
			}
			_cId = playerID;
			_cTime = Time.time;
			_cShip = val;
			return val;
		}

		internal static bool IsAboard(Vector3 pos, Ship ship)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return (Object)(object)ship != (Object)null && (Object)(object)ShipBelow(pos, 1.3f) == (Object)(object)ship;
			}
			catch
			{
				return false;
			}
		}

		internal static bool IsMoving(Ship ship)
		{
			//IL_0013: 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)
			try
			{
				Rigidbody component = ((Component)ship).GetComponent<Rigidbody>();
				int result;
				if ((Object)(object)component != (Object)null)
				{
					Vector3 velocity = component.velocity;
					result = ((((Vector3)(ref velocity)).sqrMagnitude > 1f) ? 1 : 0);
				}
				else
				{
					result = 0;
				}
				return (byte)result != 0;
			}
			catch
			{
				return false;
			}
		}

		internal static bool Excluded(GameObject go)
		{
			string text = (((Object)go).name ?? "").Replace("(Clone)", "").Trim();
			if (text.Length == 0)
			{
				return false;
			}
			string[] array = Cfg.ShipExcluded.Value.Split(new char[1] { ',' });
			foreach (string text2 in array)
			{
				if (string.Equals(text2.Trim(), text, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		internal static bool TryFindDeck(Ship ship, Player leader, CompanionController self, out Vector3 pos)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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)
			//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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: 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_00a3: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: 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_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: 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_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: 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_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			pos = Vector3.zero;
			Vector3 position = ((Component)leader).transform.position;
			int num = Mathf.Abs(((Object)self).GetInstanceID()) % 9;
			float[] array = new float[4] { 1.6f, 2.4f, 3.2f, 4f };
			float[] array2 = array;
			foreach (float num2 in array2)
			{
				for (int j = 0; j < 9; j++)
				{
					float num3 = (float)((num + j) % 9) * 40f;
					Vector3 val = Quaternion.AngleAxis(num3, Vector3.up) * Vector3.forward * num2;
					Vector3 val2 = position + val + Vector3.up * 2.5f;
					int num4 = Physics.RaycastNonAlloc(val2, Vector3.down, Hits, 5f, -5, (QueryTriggerInteraction)1);
					bool flag = false;
					RaycastHit val3 = default(RaycastHit);
					for (int k = 0; k < num4; k++)
					{
						RaycastHit val4 = Hits[k];
						if (!((Object)(object)((RaycastHit)(ref val4)).collider == (Object)null) && !(((RaycastHit)(ref val4)).normal.y < 0.6f) && !((Object)(object)((Component)((RaycastHit)(ref val4)).collider).GetComponentInParent<Ship>() != (Object)(object)ship) && !(((RaycastHit)(ref val4)).point.y < position.y - 1.2f) && !(((RaycastHit)(ref val4)).point.y > position.y + 1.2f) && (!flag || ((RaycastHit)(ref val4)).distance < ((RaycastHit)(ref val3)).distance))
						{
							val3 = val4;
							flag = true;
						}
					}
					if (!flag)
					{
						continue;
					}
					Vector3 val5 = ((RaycastHit)(ref val3)).point + Vector3.up * 0.25f;
					if (Physics.Linecast(((RaycastHit)(ref val3)).point + Vector3.up * 0.3f, ((RaycastHit)(ref val3)).point + Vector3.up * 1.6f, -5, (QueryTriggerInteraction)1))
					{
						continue;
					}
					bool flag2 = false;
					foreach (CompanionController item in CompanionController.All)
					{
						if ((Object)(object)item != (Object)null && (Object)(object)item != (Object)(object)self)
						{
							Vector3 val6 = ((Component)item).transform.position - val5;
							if (((Vector3)(ref val6)).sqrMagnitude < 1f)
							{
								flag2 = true;
								break;
							}
						}
					}
					if (!flag2)
					{
						pos = val5;
						return true;
					}
				}
			}
			return false;
		}
	}
	internal static class Loc
	{
		internal static readonly string[] Order = new string[14]
		{
			"English", "German", "French", "Spanish", "Portuguese", "Italian", "Russian", "Polish", "Turkish", "Dutch",
			"Swedish", "Chinese", "Japanese", "Korean"
		};

		internal static readonly string[] Options = new string[1] { "Auto" }.Concat(Order).ToArray();

		private static readonly Dictionary<string, string[]> Table = new Dictionary<string, string[]>
		{
			["down_say"] = new string[14]
			{
				"*knocked out*", "*bewusstlos*", "*assommé*", "*inconsciente*", "*inconsciente*", "*privo di sensi*", "*без сознания*", "*nieprzytomny*", "*bayıldı*", "*bewusteloos*",
				"*medvetslös*", "*昏迷*", "*気絶*", "*기절*"
			},
			["up_say"] = new string[14]
			{
				"*recovers*", "*erholt sich*", "*se remet*", "*se recupera*", "*se recupera*", "*si riprende*", "*приходит в себя*", "*dochodzi do siebie*", "*kendine geliyor*", "*komt bij*",
				"*piggnar till*", "*恢复了*", "*回復した*", "*회복했다*"
			},
			["star_up"] = new string[14]
			{
				"Star gained! ({0}/{1})", "Stern aufgestiegen! ({0}/{1})", "Étoile gagnée ! ({0}/{1})", "¡Estrella obtenida! ({0}/{1})", "Estrela conquistada! ({0}/{1})", "Stella ottenuta! ({0}/{1})", "Получена звезда! ({0}/{1})", "Zdobyto gwiazdkę! ({0}/{1})", "Yıldız kazanıldı! ({0}/{1})", "Ster verdiend! ({0}/{1})",
				"Stjärna intjänad! ({0}/{1})", "获得星级!({0}/{1})", "スターを獲得!({0}/{1})", "별 획득! ({0}/{1})"
			},
			["taming"] = new string[14]
			{
				"Taming", "Zähmung", "Apprivoisement", "Domesticación", "Domesticação", "Addomesticamento", "Приручение", "Oswajanie", "Evcilleştirme", "Temmen",
				"Tämjning", "驯服", "テイム", "길들이기"
			},
			["follows"] = new string[14]
			{
				"Follows: {0}", "Folgt: {0}", "Suit : {0}", "Sigue a: {0}", "Segue: {0}", "Segue: {0}", "Следует за: {0}", "Idzie za: {0}", "Takip ediyor: {0}", "Volgt: {0}",
				"Följer: {0}", "跟随:{0}", "追従:{0}", "따라감: {0}"
			},
			["paused"] = new string[14]
			{
				"Paused - hungry, feed it!", "Pausiert - hungrig, bitte füttern!", "En pause - affamé, nourrissez-le !", "En pausa: ¡tiene hambre, aliméntalo!", "Pausado - com fome, alimente-o!", "In pausa - ha fame, dagli da mangiare!", "Пауза - голоден, покормите!", "Wstrzymano - głodny, nakarm go!", "Duraklatıldı - aç, besleyin!", "Gepauzeerd - hongerig, voer het!",
				"Pausad - hungrigt, mata det!", "已暂停——饥饿,请喂食!", "一時停止 - 空腹です。餌をやってください!", "일시 중지 - 배고픔, 먹이를 주세요!"
			},
			["stars"] = new string[14]
			{
				"Stars", "Sterne", "Étoiles", "Estrellas", "Estrelas", "Stelle", "Звёзды", "Gwiazdki", "Yıldızlar", "Sterren",
				"Stjärnor", "星级", "スター", "별"
			},
			["knocked"] = new string[14]
			{
				"Knocked out", "Bewusstlos", "Assommé", "Inconsciente", "Inconsciente", "Privo di sensi", "Без сознания", "Nieprzytomny", "Bayıldı", "Bewusteloos",
				"Medvetslös", "昏迷", "気絶", "기절"
			},
			["first_aid"] = new string[14]
			{
				"First aid", "Erste Hilfe", "Premiers soins", "Primeros auxilios", "Primeiros socorros", "Primo soccorso", "Первая помощь", "Pierwsza pomoc", "İlk yardım", "Eerste hulp",
				"Första hjälpen", "急救", "応急処置", "응급처치"
			},
			["all_cmd"] = new string[14]
			{
				"All follow / stay", "Alle folgen / bleiben", "Tous suivent / restent", "Todos siguen / se quedan", "Todos seguem / ficam", "Tutti seguono / restano", "Все следуют / стоят", "Wszyscy idą za / stoją", "Hepsi takip eder / bekler", "Allen volgen / blijven",
				"Alla följer / stannar", "全体跟随 / 停留", "全員追従 / 待機", "전체 따라가기 / 대기"
			},
			["follow_n"] = new string[14]
			{
				"{0} tame(s) following you", "{0} Tame(s) folgen dir", "{0} apprivoisé(s) vous suivent", "{0} domesticado(s) te siguen", "{0} domesticado(s) estão te seguindo", "{0} addomesticato/i ti seguono", "Приручённых следует за вами: {0}", "Oswojone zwierzęta idą za tobą: {0}", "{0} evcil hayvan seni takip ediyor", "{0} getemde dier(en) volgen je",
				"{0} tämjda djur följer dig", "{0} 只驯服的动物正在跟随你", "{0}匹のテイム済みが付いてきます", "길들인 동물 {0}마리가 따라옵니다"
			},
			["stay_n"] = new string[14]
			{
				"{0} tame(s) staying", "{0} Tame(s) bleiben stehen", "{0} apprivoisé(s) restent sur place", "{0} domesticado(s) se quedan", "{0} domesticado(s) ficam parados", "{0} addomesticato/i restano fermi", "Приручённых остаётся на месте: {0}", "Oswojone zwierzęta zostają: {0}", "{0} evcil hayvan bekliyor", "{0} getemde dier(en) blijven staan",
				"{0} tämjda djur stannar", "{0} 只驯服的动物原地待命", "{0}匹のテイム済みが待機します", "길들인 동물 {0}마리가 대기합니다"
			},
			["tame_follow"] = new string[14]
			{
				"is following you", "folgt dir", "vous suit", "te sigue", "está te seguindo", "ti segue", "следует за вами", "idzie za tobą", "seni takip ediyor", "volgt je",
				"följer dig", "正在跟随你", "が付いてきます", "따라옵니다"
			},
			["tame_stay"] = new string[14]
			{
				"is staying", "bleibt stehen", "reste sur place", "se queda", "fica parado", "resta fermo", "остаётся на месте", "zostaje", "bekliyor", "blijft staan",
				"stannar", "原地待命", "が待機します", "대기합니다"
			},
			["none"] = new string[14]
			{
				"No tames in range", "Keine Tames in Reichweite", "Aucun apprivoisé à portée", "Ningún domesticado a su alcance", "Nenhum domesticado ao alcance", "Nessun addomesticato nelle vicinanze", "Нет приручённых поблизости", "Brak oswojonych w zasięgu", "Menzilde evcil hayvan yok", "Geen getemde dieren in de buurt",
				"Inga tämjda djur inom räckhåll", "范围内没有驯服的动物", "範囲内にテイム済みがいません", "범위 내에 길들인 동물이 없습니다"
			}
		};

		private static int CurrentIndex()
		{
			string text = ((Cfg.Language != null) ? Cfg.Language.Value : "English");
			if (text != "Auto")
			{
				int num = Array.IndexOf(Order, text);
				return (num >= 0) ? num : 0;
			}
			try
			{
				string text2 = ((Localization.instance != null) ? Localization.instance.GetSelectedLanguage() : "English");
				if (text2.StartsWith("Portuguese"))
				{
					text2 = "Portuguese";
				}
				if (text2.StartsWith("Chinese"))
				{
					text2 = "Chinese";
				}
				int num2 = Array.IndexOf(Order, text2);
				return (num2 >= 0) ? num2 : 0;
			}
			catch
			{
				return 0;
			}
		}

		internal static string T(string key, params object[] args)
		{
			string text = key;
			if (Table.TryGetValue(key, out var value))
			{
				int num = CurrentIndex();
				text = ((num < value.Length && !string.IsNullOrEmpty(value[num])) ? value[num] : value[0]);
			}
			try
			{
				return (args != null && args.Length != 0) ? string.Format(text, args) : text;
			}
			catch
			{
				return text;
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "Awake")]
	internal static class P_Tameable_Awake
	{
		private static void Postfix(Tameable __instance)
		{
			try
			{
				if ((Object)(object)((Component)__instance).GetComponent<CompanionController>() == (Object)null)
				{
					((Component)__instance).gameObject.AddComponent<CompanionController>();
				}
			}
			catch (Exception ex)
			{
				TameCompanionsPlugin.Log.LogWarning((object)("Tameable.Awake: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "GetHoverText")]
	internal static class P_Tameable_Hover
	{
		private static void Postfix(Tameable __instance, ref string __result)
		{
			try
			{
				if (Cfg.Enabled.Value)
				{
					CompanionController component = ((Component)__instance).GetComponent<CompanionController>();
					if ((Object)(object)component != (Object)null)
					{
						__result += component.ExtraHover();
					}
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "Interact")]
	internal static class P_Tameable_Interact
	{
		private static bool Prefix(Tameable __instance, Humanoid user, bool hold, bool alt, ref bool __result)
		{
			try
			{
				if (!Cfg.Enabled.Value)
				{
					return true;
				}
				CompanionController component = ((Component)__instance).GetComponent<CompanionController>();
				Player val = (Player)(object)((user is Player) ? user : null);
				if ((Object)(object)component == (Object)null || (Object)(object)val == (Object)null || !component.Ch.IsTamed())
				{
					return true;
				}
				if (component.IsDowned)
				{
					if (!hold && Time.time - CompanionManager.LastGroupCommand > 0.4f)
					{
						CompanionManager.LastGroupCommand = Time.time;
						component.Help();
					}
					__result = true;
					return false;
				}
				if (Cfg.DebugLog.Value)
				{
					TameCompanionsPlugin.Log.LogInfo((object)$"Interact {((Object)component).name}: hold={hold} alt={alt} gamepad={ZInput.IsGamepadActive()} locked={component.ActionLocked}");
				}
				if (!hold && !alt && __instance.m_commandable)
				{
					if (!component.ActionLocked)
					{
						CompanionManager.ToggleSingle(component, val);
					}
					__result = true;
					return false;
				}
			}
			catch (Exception ex)
			{
				TameCompanionsPlugin.Log.LogWarning((object)("Interact: " + ex.Message));
			}
			return true;
		}
	}
	[HarmonyPatch]
	internal static class P_BaseAI_Follow
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.DeclaredMethod(typeof(BaseAI), "Follow", new Type[2]
			{
				typeof(GameObject),
				typeof(float)
			}, (Type[])null);
		}

		private static bool Prepare()
		{
			return TargetMethod() != null;
		}

		private static bool Prefix(BaseAI __instance, GameObject go)
		{
			try
			{
				if (!Cfg.Enabled.Value)
				{
					return true;
				}
				if (!CompanionController.ByAi.TryGetValue(__instance, out var value) || (Object)(object)value == (Object)null)
				{
					return true;
				}
				return !value.HoldFollow(go);
			}
			catch
			{
				return true;
			}
		}
	}
	[HarmonyPatch]
	internal static class P_OnDeath
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.DeclaredMethod(typeof(Character), "OnDeath", (Type[])null, (Type[])null);
			MethodBase h = AccessTools.DeclaredMethod(typeof(Humanoid), "OnDeath", (Type[])null, (Type[])null);
			if (h != null)
			{
				yield return h;
			}
		}

		private static bool Prefix(Character __instance)
		{
			try
			{
				if (!Cfg.Enabled.Value || !Cfg.TamesProtected())
				{
					return true;
				}
				if ((Object)(object)__instance == (Object)null || __instance.IsPlayer() || !__instance.IsTamed())
				{
					return true;
				}
				if (!CompanionController.ByCharacter.TryGetValue(__instance, out var value))
				{
					return true;
				}
				if (Cfg.OnlyButcherKnifeKills.Value && value.ButcherActive)
				{
					return true;
				}
				value.EnterDowned();
				return false;
			}
			catch (Exception ex)
			{
				TameCompanionsPlugin.Log.LogWarning((object)("OnDeath: " + ex.Mes