Decompiled source of LeashMe v1.3.1

LeashMe.dll

Decompiled 17 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Splatform;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("LeashMe")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LeashMe")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("1.3.1")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.1.0")]
namespace LeashMe;

internal static class EmbeddedSprite
{
	public static Sprite Load(string fileName)
	{
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		using Stream stream = typeof(EmbeddedSprite).Assembly.GetManifestResourceStream("LeashMe." + fileName);
		if (stream == null)
		{
			Logger.LogWarning((object)("Embedded icon " + fileName + " not found."));
			return null;
		}
		byte[] array = new byte[stream.Length];
		stream.Read(array, 0, array.Length);
		Texture2D val = AssetUtils.LoadImage(array);
		return Object.op_Implicit((Object)(object)val) ? Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)) : null;
	}
}
internal class HitchingPost : MonoBehaviour, Hoverable, Interactable
{
	private const int MaxAnimals = 5;

	private static readonly int IdKey = StringExtensionMethods.GetStableHashCode("LeashMe_postId");

	private static readonly List<HitchingPost> s_posts = new List<HitchingPost>();

	private static readonly List<LeashLink> s_links = new List<LeashLink>();

	private static readonly Random s_random = new Random();

	private ZNetView m_nview;

	private Piece m_piece;

	private int m_level;

	private GameObject m_wrap;

	private bool m_hasRopePoint;

	private Vector3 m_ropePoint;

	public long Id
	{
		get
		{
			if (!Object.op_Implicit((Object)(object)m_nview) || !m_nview.IsValid())
			{
				return 0L;
			}
			return m_nview.GetZDO().GetLong(IdKey, 0L);
		}
	}

	public Vector3 RopePoint
	{
		get
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (!m_hasRopePoint)
			{
				m_hasRopePoint = true;
				m_ropePoint = ((Component)this).transform.TransformPoint(0f, HitchingPostPiece.GetRopeHeight(((Component)this).gameObject), 0f);
			}
			return m_ropePoint;
		}
	}

	public static HitchingPost Find(long id)
	{
		if (id == 0L)
		{
			return null;
		}
		foreach (HitchingPost s_post in s_posts)
		{
			if (Object.op_Implicit((Object)(object)s_post) && s_post.Id == id)
			{
				return s_post;
			}
		}
		return null;
	}

	private void Start()
	{
		m_nview = ((Component)this).GetComponent<ZNetView>();
		m_piece = ((Component)this).GetComponent<Piece>();
		m_level = HitchingPostPiece.GetLevel(((Component)this).gameObject);
		Transform obj = ((Component)this).transform.Find("leatherwrap");
		m_wrap = ((obj != null) ? ((Component)obj).gameObject : null);
		if (Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid())
		{
			s_posts.Add(this);
			EnsureId();
		}
	}

	private void OnDestroy()
	{
		s_posts.Remove(this);
	}

	private void Update()
	{
		EnsureId();
		UpdateWrap();
	}

	private void UpdateWrap()
	{
		if (Object.op_Implicit((Object)(object)m_wrap))
		{
			bool flag = Id != 0L && CountTied() > 0;
			if (m_wrap.activeSelf != flag)
			{
				m_wrap.SetActive(flag);
			}
		}
	}

	private void EnsureId()
	{
		if (Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid() && m_nview.IsOwner() && Id == 0L)
		{
			long num;
			do
			{
				num = ((long)s_random.Next() << 32) ^ (uint)s_random.Next();
			}
			while (num == 0L);
			m_nview.GetZDO().Set(IdKey, num);
		}
	}

	public string GetHoverText()
	{
		string text = GetHoverName();
		if (!LocalHasLeash((Humanoid)(object)Player.m_localPlayer) || Id == 0L)
		{
			return text;
		}
		LocalLeash.GetLinks(s_links, confirmedOnly: true);
		if (s_links.Count > 0)
		{
			text = text + "\n" + ((CountMisfits(out var reason) < s_links.Count) ? Localization.instance.Localize("[<color=yellow><b>$KEY_Use</b></color>] $leashme_tie") : reason);
		}
		if (CountTied() > 0)
		{
			text += Localization.instance.Localize((ZInput.IsNonClassicFunctionality() && ZInput.IsGamepadActive()) ? "\n[<color=yellow><b>$KEY_AltKeys + $KEY_Use</b></color>] $leashme_untie" : "\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] $leashme_untie");
		}
		return text;
	}

	public string GetHoverName()
	{
		if (!Object.op_Implicit((Object)(object)m_piece))
		{
			return "";
		}
		return Localization.instance.Localize(m_piece.m_name);
	}

	public float GetHoverOffset()
	{
		return 0f;
	}

	public bool Interact(Humanoid user, bool hold, bool alt)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		if (hold || !LocalHasLeash(user) || Id == 0L)
		{
			return false;
		}
		Player player = (Player)user;
		if (alt)
		{
			Untie(player);
		}
		else
		{
			Tie(player);
		}
		return true;
	}

	public bool UseItem(Humanoid user, ItemData item)
	{
		return false;
	}

	private static bool LocalHasLeash(Humanoid user)
	{
		if (Object.op_Implicit((Object)(object)user) && (Object)(object)user == (Object)(object)Player.m_localPlayer)
		{
			return LeashItem.IsEquipped(user);
		}
		return false;
	}

	private int CountTied()
	{
		long id = Id;
		int num = 0;
		foreach (LeashLink item in LeashLink.All)
		{
			if (item.PostId == id)
			{
				num++;
			}
		}
		return num;
	}

	private bool Fits(LeashLink link)
	{
		if (link.IsInPostReach(this))
		{
			return LeashItem.IsStrongEnough(m_level, link.Tameable);
		}
		return false;
	}

	private int CountMisfits(out string reason)
	{
		int num = 0;
		string text = "";
		int num2 = 0;
		string text2 = "";
		foreach (LeashLink s_link in s_links)
		{
			if (!s_link.IsInPostReach(this))
			{
				num2++;
				text2 = s_link.Tameable.GetHoverName();
			}
			else if (!Fits(s_link))
			{
				num++;
				text = s_link.Tameable.GetHoverName();
			}
		}
		reason = ((num == 1) ? Localization.instance.Localize("$leashme_post_too_weak", new string[1] { text }) : ((num > 1) ? Localization.instance.Localize("$leashme_post_too_weak_many", new string[1] { num.ToString() }) : ((num2 == 1) ? Localization.instance.Localize("$leashme_post_too_far", new string[1] { text2 }) : ((num2 > 1) ? Localization.instance.Localize("$leashme_post_too_far_many", new string[1] { num2.ToString() }) : ""))));
		return num + num2;
	}

	private void Tie(Player player)
	{
		long id = Id;
		int num = CountTied();
		int num2 = 0;
		LocalLeash.GetLinks(s_links, confirmedOnly: true);
		foreach (LeashLink s_link in s_links)
		{
			if (Fits(s_link))
			{
				if (num >= 5)
				{
					num2++;
					continue;
				}
				s_link.RequestTie(id);
				num++;
			}
		}
		if (CountMisfits(out var reason) > 0)
		{
			((Character)player).Message((MessageType)2, reason, 0, (Sprite)null, false);
		}
		else if (num2 > 0)
		{
			((Character)player).Message((MessageType)2, (num2 == 1) ? "$leashme_post_no_room" : Localization.instance.Localize("$leashme_post_no_room_many", new string[1] { num2.ToString() }), 0, (Sprite)null, false);
		}
	}

	private void Untie(Player player)
	{
		long id = Id;
		bool flag = false;
		bool flag2 = false;
		foreach (LeashLink item in LeashLink.All)
		{
			if (item.PostId == id && LeashLink.CanLeash(item.Tameable, player))
			{
				if (!LeashItem.IsStrongEnough((Humanoid)(object)player, item.Tameable))
				{
					flag2 = true;
				}
				else if (LocalLeash.IsAtLimit(item))
				{
					flag = true;
				}
				else
				{
					LocalLeash.Leash(item, player);
				}
			}
		}
		if (flag)
		{
			((Character)player).Message((MessageType)2, "$leashme_limit", 0, (Sprite)null, false);
		}
		else if (flag2)
		{
			((Character)player).Message((MessageType)2, "$leashme_too_weak", 0, (Sprite)null, false);
		}
	}
}
internal static class HitchingPostPiece
{
	private const string BasePrefabName = "wood_pole_log";

	private const string BundleName = "leashme";

	private const string SilverPrefabName = "piece_chest_treasure";

	private const string SilverMaterialName = "BlackMetalChest_silver_mat";

	private const float SilverMetalColor = 0.5f;

	public const string WrapName = "leatherwrap";

	private const string WrapModelName = "HitchingPost_LeatherWrap";

	private const string HandWrapName = "LeashMe_HandWrap";

	private static readonly (string Prefab, string Name, int Level, float Health, string Model, float RopeHeight, Vector3 WrapScale, float WrapY, (string Item, int Amount)[] Resources)[] Pieces = new(string, string, int, float, string, float, Vector3, float, (string, int)[])[3]
	{
		("LeashMe_HitchingPost", "$leashme_post", 1, 1000f, "HitchingPost_Corewood", 0.674f, Vector3.one, 0f, new(string, int)[1] { ("RoundLog", 3) }),
		("LeashMe_HitchingPostSilver", "$leashme_post_silver", 2, 2000f, "HitchingPost_Silver", 0.664f, new Vector3(1.228024f, 1.051184f, 1.22486f), -0.043301f, new(string, int)[2]
		{
			("RoundLog", 3),
			("Silver", 10)
		}),
		("LeashMe_HitchingPostBlackMetal", "$leashme_post_blackmetal", 3, 4000f, "HitchingPost_BlackMetal", 0.649f, new Vector3(1.58542f, 1.157886f, 1.57565f), -0.126443f, new(string, int)[2]
		{
			("RoundLog", 3),
			("BlackMetal", 20)
		})
	};

	private static readonly Dictionary<string, int> Levels = Pieces.ToDictionary(((string Prefab, string Name, int Level, float Health, string Model, float RopeHeight, Vector3 WrapScale, float WrapY, (string Item, int Amount)[] Resources) p) => p.Prefab, ((string Prefab, string Name, int Level, float Health, string Model, float RopeHeight, Vector3 WrapScale, float WrapY, (string Item, int Amount)[] Resources) p) => p.Level);

	private static readonly Dictionary<string, float> RopeHeights = Pieces.ToDictionary(((string Prefab, string Name, int Level, float Health, string Model, float RopeHeight, Vector3 WrapScale, float WrapY, (string Item, int Amount)[] Resources) p) => p.Prefab, ((string Prefab, string Name, int Level, float Health, string Model, float RopeHeight, Vector3 WrapScale, float WrapY, (string Item, int Amount)[] Resources) p) => p.RopeHeight);

	public static void Register()
	{
		PrefabManager.OnVanillaPrefabsAvailable += AddPieces;
	}

	public static int GetLevel(GameObject go)
	{
		if (!Levels.TryGetValue(Utils.GetPrefabName(go), out var value))
		{
			return 0;
		}
		return value;
	}

	public static float GetRopeHeight(GameObject go)
	{
		if (!RopeHeights.TryGetValue(Utils.GetPrefabName(go), out var value))
		{
			return 0f;
		}
		return value;
	}

	private static void AddPieces()
	{
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_015c: Expected O, but got Unknown
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: 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_020b: Expected O, but got Unknown
		//IL_0248: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: Expected O, but got Unknown
		//IL_0270: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
		PrefabManager.OnVanillaPrefabsAvailable -= AddPieces;
		AssetBundle bundle = AssetUtils.LoadAssetBundleFromResources("leashme", typeof(HitchingPostPiece).Assembly);
		if (!Object.op_Implicit((Object)(object)bundle))
		{
			Logger.LogError((object)"Asset bundle not found; hitching posts not added.");
			return;
		}
		Dictionary<string, GameObject> dictionary = Pieces.ToDictionary(((string Prefab, string Name, int Level, float Health, string Model, float RopeHeight, Vector3 WrapScale, float WrapY, (string Item, int Amount)[] Resources) p) => p.Model, ((string Prefab, string Name, int Level, float Health, string Model, float RopeHeight, Vector3 WrapScale, float WrapY, (string Item, int Amount)[] Resources) p) => bundle.LoadAsset<GameObject>(p.Model));
		GameObject val = bundle.LoadAsset<GameObject>("HitchingPost_LeatherWrap");
		GameObject obj = bundle.LoadAsset<GameObject>("LeashMe_HandWrap");
		object obj2;
		if (obj == null)
		{
			obj2 = null;
		}
		else
		{
			MeshRenderer componentInChildren = obj.GetComponentInChildren<MeshRenderer>(true);
			obj2 = ((componentInChildren != null) ? ((Renderer)componentInChildren).sharedMaterial : null);
		}
		Material val2 = (Material)obj2;
		bundle.Unload(false);
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2))
		{
			Logger.LogWarning((object)"Hitching post leather wrap not found; posts without wrap.");
		}
		Material val3 = VanillaMaterials.Find("piece_chest_treasure", "BlackMetalChest_silver_mat");
		Material blackMetal = VanillaMaterials.BlackMetal;
		if (dictionary.Values.Any((GameObject m) => !Object.op_Implicit((Object)(object)m)) || !Object.op_Implicit((Object)(object)blackMetal) || !Object.op_Implicit((Object)(object)val3))
		{
			Logger.LogError((object)"Hitching post models or materials not found; hitching posts not added.");
			return;
		}
		val3 = new Material(val3)
		{
			name = ((Object)val3).name
		};
		val3.SetColor("_MetalColor", new Color(0.5f, 0.5f, 0.5f, 1f));
		(string, string, int, float, string, float, Vector3, float, (string, int)[])[] pieces = Pieces;
		for (int num = 0; num < pieces.Length; num++)
		{
			(string, string, int, float, string, float, Vector3, float, (string, int)[]) tuple = pieces[num];
			PieceConfig val4 = new PieceConfig
			{
				Name = tuple.Item2,
				Description = "$leashme_post_desc",
				PieceTable = PieceTables.Hammer,
				CraftingStation = "piece_workbench",
				Requirements = ((IEnumerable<(string, int)>)tuple.Rest.Item2).Select((Func<(string, int), RequirementConfig>)(((string Item, int Amount) r) => new RequirementConfig(r.Item, r.Amount, 0, true))).ToArray()
			};
			Sprite val5 = EmbeddedSprite.Load($"buildmenu_icon_hitchingpost{tuple.Item3}_128.png");
			if (Object.op_Implicit((Object)(object)val5))
			{
				val4.Icon = val5;
			}
			CustomPiece val6 = new CustomPiece(tuple.Item1, "wood_pole_log", val4);
			if (!Object.op_Implicit((Object)(object)val6.PiecePrefab))
			{
				Logger.LogError((object)"wood_pole_log not found; hitching posts not added.");
				break;
			}
			val6.Piece.m_category = (PieceCategory)0;
			val6.Piece.m_usage = (UsageTagFlags)1;
			val6.Piece.m_notOnWood = true;
			Material head = ((tuple.Item3 == 2) ? val3 : ((tuple.Item3 == 3) ? blackMetal : null));
			if (!ReplaceModel(val6.PiecePrefab, dictionary[tuple.Item5], head))
			{
				Logger.LogError((object)"wood_pole_log has no core wood material; hitching posts not added.");
				break;
			}
			if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2))
			{
				AddWrap(val6.PiecePrefab, val, val2, tuple.Item7, tuple.Rest.Item1);
			}
			WearNTear component = val6.PiecePrefab.GetComponent<WearNTear>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.m_health = tuple.Item4;
			}
			val6.PiecePrefab.AddComponent<HitchingPost>();
			PieceManager.Instance.AddPiece(val6);
		}
	}

	private static bool ReplaceModel(GameObject prefab, GameObject model, Material head)
	{
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Expected O, but got Unknown
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c1: 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_01dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0205: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0253: Unknown result type (might be due to invalid IL or missing references)
		Transform obj = prefab.transform.Find("New");
		object obj2;
		if (obj == null)
		{
			obj2 = null;
		}
		else
		{
			MeshRenderer componentInChildren = ((Component)obj).GetComponentInChildren<MeshRenderer>(true);
			obj2 = ((componentInChildren != null) ? ((Renderer)componentInChildren).sharedMaterial : null);
		}
		Material val = (Material)obj2;
		Transform val2 = prefab.transform.Find("collider");
		if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2))
		{
			return false;
		}
		val = new Material(val)
		{
			name = ((Object)val).name
		};
		val.SetFloat("_RippleDistance", 0f);
		WearNTear component = prefab.GetComponent<WearNTear>();
		if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_snow))
		{
			Object.DestroyImmediate((Object)(object)((Component)component.m_snow).gameObject);
		}
		int layer = ((Component)val2).gameObject.layer;
		string tag = ((Component)val2).tag;
		string[] array = new string[3] { "New", "WornBroken", "collider" };
		foreach (string text in array)
		{
			Transform val3 = prefab.transform.Find(text);
			if (Object.op_Implicit((Object)(object)val3))
			{
				Object.DestroyImmediate((Object)(object)((Component)val3).gameObject);
			}
		}
		LODGroup component2 = prefab.GetComponent<LODGroup>();
		if (Object.op_Implicit((Object)(object)component2))
		{
			Object.DestroyImmediate((Object)(object)component2);
		}
		GameObject val4 = Object.Instantiate<GameObject>(model, prefab.transform, false);
		((Object)val4).name = "model";
		MeshRenderer componentInChildren2 = val4.GetComponentInChildren<MeshRenderer>();
		Mesh sharedMesh = val4.GetComponentInChildren<MeshFilter>().sharedMesh;
		((Renderer)componentInChildren2).sharedMaterials = (Material[])(object)((!Object.op_Implicit((Object)(object)head)) ? new Material[1] { val } : new Material[2] { val, head });
		Transform[] componentsInChildren = val4.GetComponentsInChildren<Transform>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			((Component)componentsInChildren[i]).gameObject.layer = layer;
		}
		Bounds bounds = sharedMesh.bounds;
		float num = Mathf.Min(((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.z);
		GameObject val5 = new GameObject("collider")
		{
			layer = layer,
			tag = tag
		};
		val5.transform.SetParent(prefab.transform, false);
		BoxCollider obj3 = val5.AddComponent<BoxCollider>();
		obj3.center = ((Bounds)(ref bounds)).center;
		obj3.size = new Vector3(num, ((Bounds)(ref bounds)).size.y, num);
		if (Object.op_Implicit((Object)(object)component))
		{
			component.m_new = val4;
			component.m_worn = val4;
			component.m_broken = val4;
			component.m_snow = null;
		}
		KeepBottomSnapPoint(prefab, ((Bounds)(ref bounds)).min.y);
		return true;
	}

	private static void AddWrap(GameObject prefab, GameObject model, Material leather, Vector3 scale, float offsetY)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(model, prefab.transform, false);
		((Object)val).name = "leatherwrap";
		val.transform.localPosition = new Vector3(0f, offsetY, 0f);
		val.transform.localRotation = Quaternion.identity;
		val.transform.localScale = scale;
		int layer = ((Component)prefab.transform.Find("model")).gameObject.layer;
		Transform[] componentsInChildren = val.GetComponentsInChildren<Transform>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			((Component)componentsInChildren[i]).gameObject.layer = layer;
		}
		MeshRenderer[] componentsInChildren2 = val.GetComponentsInChildren<MeshRenderer>(true);
		for (int i = 0; i < componentsInChildren2.Length; i++)
		{
			((Renderer)componentsInChildren2[i]).sharedMaterial = leather;
		}
		val.SetActive(false);
	}

	private static void KeepBottomSnapPoint(GameObject prefab, float footY)
	{
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		List<Transform> list = (from t in prefab.GetComponentsInChildren<Transform>(true)
			where ((Component)t).CompareTag("snappoint")
			orderby prefab.transform.InverseTransformPoint(t.position).y
			select t).ToList();
		foreach (Transform item in list.Skip(1))
		{
			Object.DestroyImmediate((Object)(object)((Component)item).gameObject);
		}
		if (list.Count > 0)
		{
			list[0].localPosition = new Vector3(0f, footY, 0f);
		}
	}
}
internal static class LeashItem
{
	public const string PrefabName = "LeashMe_Leash";

	private const string BundleName = "leashme";

	private const string HandWrapName = "LeashMe_HandWrap";

	private const string GroundCoilName = "LeashMe_GroundCoil";

	private const string StandObjectName = "attachobj";

	private const string StandCoilName = "coil";

	private const string StandHangingName = "hanging";

	private const string WallStandName = "itemstand";

	public static readonly int PrefabHash = StringExtensionMethods.GetStableHashCode("LeashMe_Leash");

	private const int MaxLevel = 3;

	private static readonly string[] Resources = new string[3] { "LeatherScraps", "WolfHairBundle", "LinenThread" };

	private static readonly int[][] AmountsPerLevel = new int[3][]
	{
		new int[3] { 10, 5, 5 },
		new int[3] { 0, 5, 0 },
		new int[3] { 0, 0, 5 }
	};

	private static readonly Dictionary<string, int> RequiredLevels = new Dictionary<string, int>
	{
		{ "Boar", 1 },
		{ "Hen", 1 },
		{ "Wolf", 2 }
	};

	private static Recipe s_recipe;

	public static void Register()
	{
		PrefabManager.OnVanillaPrefabsAvailable += AddItem;
	}

	public static bool IsEquipped(Humanoid humanoid)
	{
		return IsLeash(Object.op_Implicit((Object)(object)humanoid) ? humanoid.m_leftItem : null);
	}

	public static bool IsHeld(Humanoid humanoid)
	{
		if (!IsEquipped(humanoid))
		{
			return IsLeash(Object.op_Implicit((Object)(object)humanoid) ? humanoid.m_hiddenLeftItem : null);
		}
		return true;
	}

	public static bool IsHeld(ZDO playerZdo)
	{
		if (playerZdo.GetInt(ZDOVars.s_leftItem, 0) != PrefabHash)
		{
			return playerZdo.GetInt(ZDOVars.s_leftBackItem, 0) == PrefabHash;
		}
		return true;
	}

	public static bool IsLeash(ItemData item)
	{
		if (item != null && Object.op_Implicit((Object)(object)item.m_dropPrefab))
		{
			return ((Object)item.m_dropPrefab).name == "LeashMe_Leash";
		}
		return false;
	}

	public static bool IsStrongEnough(Humanoid humanoid, Tameable tameable)
	{
		if (IsEquipped(humanoid))
		{
			return IsStrongEnough(humanoid.m_leftItem.m_quality, tameable);
		}
		return false;
	}

	public static bool IsStrongEnough(int level, Tameable tameable)
	{
		if (!RequiredLevels.TryGetValue(Utils.GetPrefabName(((Component)tameable).gameObject), out var value))
		{
			value = 3;
		}
		return level >= value;
	}

	public static bool TryGetAmount(Requirement requirement, int quality, out int amount)
	{
		amount = 0;
		Requirement[] array = (Object.op_Implicit((Object)(object)s_recipe) ? s_recipe.m_resources : null);
		if (array == null)
		{
			return false;
		}
		int num = Array.IndexOf(array, requirement);
		if (num < 0 || num >= AmountsPerLevel.Length)
		{
			return false;
		}
		amount = AmountsPerLevel[num][Mathf.Clamp(quality, 1, 3) - 1];
		return true;
	}

	private static void AddItem()
	{
		//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)
		//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_0037: 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_0051: Expected O, but got Unknown
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Expected O, but got Unknown
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Expected O, but got Unknown
		PrefabManager.OnVanillaPrefabsAvailable -= AddItem;
		ItemConfig val = new ItemConfig
		{
			Name = "$leashme_leash",
			Description = "$leashme_leash_desc",
			CraftingStation = "piece_workbench",
			MinStationLevel = 3,
			Requirements = (RequirementConfig[])(object)new RequirementConfig[Resources.Length]
		};
		for (int i = 0; i < Resources.Length; i++)
		{
			val.Requirements[i] = new RequirementConfig(Resources[i], AmountsPerLevel[i][0], 1, false);
		}
		Sprite val2 = EmbeddedSprite.Load("inventory_icon_leine_128.png");
		if (Object.op_Implicit((Object)(object)val2))
		{
			val.Icons = (Sprite[])(object)new Sprite[1] { val2 };
		}
		CustomItem val3 = new CustomItem("LeashMe_Leash", "ShieldWood", val);
		if (!Object.op_Implicit((Object)(object)val3.ItemPrefab))
		{
			Logger.LogError((object)"ShieldWood prefab not found; leash item not added.");
			return;
		}
		SharedData shared = val3.ItemDrop.m_itemData.m_shared;
		shared.m_maxQuality = 3;
		shared.m_variants = 1;
		shared.m_useDurability = false;
		shared.m_canBeReparied = false;
		shared.m_weight = 0.5f;
		shared.m_movementModifier = 0f;
		shared.m_eitrRegenModifier = 0f;
		shared.m_homeItemsStaminaModifier = 0f;
		shared.m_heatResistanceModifier = 0f;
		shared.m_jumpStaminaModifier = 0f;
		shared.m_attackStaminaModifier = 0f;
		shared.m_blockStaminaModifier = 0f;
		shared.m_dodgeStaminaModifier = 0f;
		shared.m_swimStaminaModifier = 0f;
		shared.m_sneakStaminaModifier = 0f;
		shared.m_runStaminaModifier = 0f;
		shared.m_damageModifiers.Clear();
		shared.m_equipStatusEffect = null;
		shared.m_setName = "";
		shared.m_setSize = 0;
		shared.m_setStatusEffect = null;
		shared.m_blockPower = 0f;
		shared.m_blockPowerPerLevel = 0f;
		shared.m_deflectionForce = 0f;
		shared.m_deflectionForcePerLevel = 0f;
		shared.m_timedBlockBonus = 0f;
		shared.m_blockAdrenaline = 0f;
		shared.m_perfectBlockAdrenaline = 0f;
		ReplaceModels(val3.ItemPrefab);
		ItemManager.Instance.AddItem(val3);
		CustomRecipe recipe = val3.Recipe;
		s_recipe = ((recipe != null) ? recipe.Recipe : null);
		if (!Object.op_Implicit((Object)(object)s_recipe) || s_recipe.m_resources == null || s_recipe.m_resources.Length != Resources.Length)
		{
			Logger.LogWarning((object)"Leash recipe resources not as expected; upgrade costs fall back to vanilla scaling.");
		}
	}

	public static void OnStandVisual(ItemStand stand, int itemHash)
	{
		if (itemHash == PrefabHash && Object.op_Implicit((Object)(object)stand.m_visualItem))
		{
			stand.m_visualItem.SetActive(true);
			bool flag = IsWallStand(stand);
			Transform val = stand.m_visualItem.transform.Find("coil");
			Transform val2 = stand.m_visualItem.transform.Find("hanging");
			if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2))
			{
				((Component)val).gameObject.SetActive(!flag);
				((Component)val2).gameObject.SetActive(flag);
			}
		}
	}

	public static bool IsWallStand(ItemStand stand)
	{
		return Utils.GetPrefabName(Object.op_Implicit((Object)(object)stand.m_nview) ? ((Component)stand.m_nview).gameObject : ((Component)stand).gameObject) == "itemstand";
	}

	private static void ReplaceModels(GameObject itemPrefab)
	{
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: 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_0108: Expected O, but got Unknown
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0236: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_025f: Unknown result type (might be due to invalid IL or missing references)
		//IL_027d: 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_02b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02db: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0309: Unknown result type (might be due to invalid IL or missing references)
		//IL_0313: Unknown result type (might be due to invalid IL or missing references)
		//IL_034c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0356: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: 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_01d3: 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_01e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
		AssetBundle val = AssetUtils.LoadAssetBundleFromResources("leashme", typeof(LeashItem).Assembly);
		if (!Object.op_Implicit((Object)(object)val))
		{
			return;
		}
		GameObject val2 = val.LoadAsset<GameObject>("LeashMe_HandWrap");
		GameObject val3 = val.LoadAsset<GameObject>("LeashMe_GroundCoil");
		if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val3))
		{
			Logger.LogError((object)"Leash models not found in asset bundle; leash keeps the shield model.");
			val.Unload(false);
			return;
		}
		int layer = itemPrefab.layer;
		string[] array = new string[2] { "attach", "attach_back" };
		foreach (string text in array)
		{
			Transform val4 = itemPrefab.transform.Find(text);
			if (Object.op_Implicit((Object)(object)val4))
			{
				if (text == "attach")
				{
					layer = ((Component)val4).gameObject.layer;
				}
				Object.DestroyImmediate((Object)(object)((Component)val4).gameObject);
			}
		}
		GameObject val5 = new GameObject("attach_back");
		val5.transform.SetParent(itemPrefab.transform, false);
		val5.transform.SetSiblingIndex(0);
		GameObject val6 = new GameObject("attach");
		val6.transform.SetParent(itemPrefab.transform, false);
		Transform transform = new GameObject("LeashMe_HandWrap").transform;
		transform.SetParent(val6.transform, false);
		transform.localPosition = new Vector3(0.09f, 0.03f, -0.027f);
		transform.localEulerAngles = new Vector3(60f, 130f, 220f);
		transform.localScale = Vector3.one * 1.9f;
		GameObject val7 = Object.Instantiate<GameObject>(val2, transform, false);
		MeshFilter componentInChildren = val7.GetComponentInChildren<MeshFilter>();
		if (Object.op_Implicit((Object)(object)componentInChildren) && Object.op_Implicit((Object)(object)componentInChildren.sharedMesh))
		{
			Transform transform2 = ((Component)componentInChildren).transform;
			Bounds bounds = componentInChildren.sharedMesh.bounds;
			Vector3 val8 = transform2.TransformPoint(((Bounds)(ref bounds)).center);
			val7.transform.localPosition = -transform.InverseTransformPoint(val8);
		}
		Transform transform3 = new GameObject("attachobj").transform;
		((Component)transform3).gameObject.SetActive(false);
		transform3.SetParent(val6.transform, false);
		GameObject obj = Object.Instantiate<GameObject>(val3, transform3, false);
		((Object)obj).name = "coil";
		obj.transform.localScale = Vector3.one * 2.5f;
		obj.transform.localEulerAngles = new Vector3(0f, 270f, 0f);
		obj.transform.localPosition = new Vector3(-0.14f, 0f, -0.125f);
		Transform transform4 = new GameObject("hanging").transform;
		transform4.SetParent(transform3, false);
		transform4.localScale = new Vector3(1f, 1f, 1.5f);
		GameObject obj2 = Object.Instantiate<GameObject>(val3, transform4, false);
		obj2.transform.localPosition = new Vector3(-0.05f, -0.11f, -0.242f);
		obj2.transform.localEulerAngles = new Vector3(0f, 250f, 0f);
		obj2.transform.localScale = Vector3.one * 1.9f;
		((Component)transform4).gameObject.SetActive(false);
		GameObject val9 = Object.Instantiate<GameObject>(val3, itemPrefab.transform, false);
		((Object)val9).name = "LeashMe_GroundCoil";
		val9.transform.localScale = Vector3.one * 2.5f;
		MeshFilter[] componentsInChildren = val9.GetComponentsInChildren<MeshFilter>();
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			((Component)componentsInChildren[i]).gameObject.AddComponent<BoxCollider>();
		}
		Transform[] componentsInChildren2 = val9.GetComponentsInChildren<Transform>();
		for (int i = 0; i < componentsInChildren2.Length; i++)
		{
			((Component)componentsInChildren2[i]).gameObject.layer = layer;
		}
		val6.SetActive(false);
		val.Unload(false);
	}
}
internal class LeashLine : MonoBehaviour
{
	private const int Points = 12;

	private const float MaxSag = 1f;

	private const float WidthScale = 0.4f;

	private const float TautDistance = 12f;

	private const string HeadBoneName = "DEF-head";

	private static readonly Color LeatherBrown = new Color(0.578f, 0.282f, 0.119f);

	private static LineRenderer s_template;

	private static Material s_material;

	private static bool s_templateMissing;

	private Tameable m_tameable;

	private Transform m_head;

	private LineRenderer m_line;

	public static void Attach(Tameable tameable)
	{
		LeashLine leashLine = ((Component)tameable).gameObject.AddComponent<LeashLine>();
		leashLine.m_tameable = tameable;
		leashLine.m_head = FindHead(tameable);
	}

	private static Transform FindHead(Tameable tameable)
	{
		Character character = tameable.m_character;
		if (!Object.op_Implicit((Object)(object)character) || Object.op_Implicit((Object)(object)character.m_head))
		{
			if (!Object.op_Implicit((Object)(object)character))
			{
				return null;
			}
			return character.m_head;
		}
		return ((IEnumerable<Transform>)((Component)tameable).GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name == "DEF-head"));
	}

	private void LateUpdate()
	{
		//IL_005b: 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_0060: 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_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: 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_00b9: 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)
		Character character = m_tameable.m_character;
		if (!Object.op_Implicit((Object)(object)character) || !TryGetStart(out var start) || !EnsureLine())
		{
			if (Object.op_Implicit((Object)(object)m_line))
			{
				((Renderer)m_line).enabled = false;
			}
			return;
		}
		Vector3 val = (Object.op_Implicit((Object)(object)m_head) ? m_head.position : character.GetCenterPoint());
		float num = 1f * Mathf.Clamp01(1f - Vector3.Distance(start, val) / 12f);
		for (int i = 0; i < 12; i++)
		{
			float num2 = (float)i / 11f;
			m_line.SetPosition(i, Vector3.Lerp(start, val, num2) + Vector3.down * (num * 4f * num2 * (1f - num2)));
		}
		((Renderer)m_line).enabled = true;
	}

	private bool TryGetStart(out Vector3 start)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: 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_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: 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)
		start = Vector3.zero;
		long post = LeashLink.GetPost(m_tameable.m_nview);
		if (post != 0L)
		{
			HitchingPost hitchingPost = HitchingPost.Find(post);
			if (!Object.op_Implicit((Object)(object)hitchingPost))
			{
				return false;
			}
			start = hitchingPost.RopePoint;
			return true;
		}
		ZDOID holder = LeashLink.GetHolder(m_tameable);
		GameObject val = ((((ZDOID)(ref holder)).IsNone() || !Object.op_Implicit((Object)(object)ZNetScene.instance)) ? null : ZNetScene.instance.FindInstance(holder));
		Player val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Player>() : null);
		if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)((Humanoid)val2).m_visEquipment) || !Object.op_Implicit((Object)(object)((Humanoid)val2).m_visEquipment.m_leftHand))
		{
			return false;
		}
		start = ((Humanoid)val2).m_visEquipment.m_leftHand.position;
		return true;
	}

	private bool EnsureLine()
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Expected O, but got Unknown
		//IL_00a1: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)m_line))
		{
			return true;
		}
		LineRenderer template = GetTemplate();
		if (!Object.op_Implicit((Object)(object)template))
		{
			return false;
		}
		GameObject val = new GameObject("LeashMe_Line");
		val.transform.SetParent(((Component)this).transform, false);
		m_line = val.AddComponent<LineRenderer>();
		m_line.useWorldSpace = true;
		m_line.positionCount = 12;
		((Renderer)m_line).sharedMaterial = GetMaterial(template);
		m_line.widthCurve = template.widthCurve;
		m_line.widthMultiplier = template.widthMultiplier * 0.4f;
		m_line.textureMode = template.textureMode;
		m_line.generateLightingData = true;
		m_line.alignment = template.alignment;
		((Renderer)m_line).shadowCastingMode = ((Renderer)template).shadowCastingMode;
		return true;
	}

	private static Material GetMaterial(LineRenderer template)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Expected O, but got Unknown
		if (Object.op_Implicit((Object)(object)s_material))
		{
			return s_material;
		}
		s_material = new Material(((Renderer)template).sharedMaterial)
		{
			color = LeatherBrown,
			mainTexture = null
		};
		s_material.SetTexture("_BumpMap", (Texture)null);
		s_material.SetFloat("_Metallic", 0f);
		s_material.SetFloat("_Glossiness", 0.1f);
		return s_material;
	}

	private static LineRenderer GetTemplate()
	{
		if (Object.op_Implicit((Object)(object)s_template) || s_templateMissing || !Object.op_Implicit((Object)(object)ObjectDB.instance))
		{
			return s_template;
		}
		s_template = (from data in ObjectDB.instance.m_StatusEffects.OfType<SE_Harpooned>().SelectMany((SE_Harpooned effect) => ((StatusEffect)effect).m_startEffects.m_effectPrefabs)
			where Object.op_Implicit((Object)(object)data.m_prefab)
			select data.m_prefab.GetComponentInChildren<LineRenderer>(true)).FirstOrDefault((Func<LineRenderer, bool>)((LineRenderer line) => Object.op_Implicit((Object)(object)line)));
		if (!Object.op_Implicit((Object)(object)s_template))
		{
			s_templateMissing = true;
			Logger.LogWarning((object)"Harpoon line not found; leash rope is not shown.");
		}
		return s_template;
	}
}
internal class LeashLink : MonoBehaviour
{
	private static readonly KeyValuePair<int, int> HolderKey = ZDO.GetHashZDOID("LeashMe_holder");

	private static readonly int PostKey = StringExtensionMethods.GetStableHashCode("LeashMe_post");

	private static readonly int PostPosKey = StringExtensionMethods.GetStableHashCode("LeashMe_postPos");

	private const string RpcLeash = "LeashMe_Leash";

	private const string RpcRelease = "LeashMe_Release";

	private const string RpcRequestOwnership = "LeashMe_RequestOwnership";

	private const string RpcTie = "LeashMe_Tie";

	private const float HardLimit = 18f;

	private const string SpiritCallerSuffix = "_spiritcaller";

	private const float LoxHardLimit = 30f;

	private const float CheckInterval = 1f;

	private const float GraceSeconds = 3f;

	private const float MaxDropInFront = 2f;

	private static readonly List<LeashLink> s_links = new List<LeashLink>();

	private Tameable m_tameable;

	private float m_hardLimit;

	private float m_nextCheck;

	private float m_invalidSince = -1f;

	public Tameable Tameable => m_tameable;

	public static IReadOnlyList<LeashLink> All => s_links;

	public long PostId => GetPost(m_tameable.m_nview);

	public static bool IsSpiritCaller(GameObject go)
	{
		return Utils.GetPrefabName(go).EndsWith("_spiritcaller");
	}

	public static void Attach(Tameable tameable)
	{
		if (tameable.m_nview.IsValid() && !Object.op_Implicit((Object)(object)((Component)tameable).GetComponent<LeashLink>()) && !IsSpiritCaller(((Component)tameable).gameObject))
		{
			LeashLink leashLink = ((Component)tameable).gameObject.AddComponent<LeashLink>();
			leashLink.Init(tameable);
			LeashLine.Attach(tameable);
			LocalLeash.Adopt(leashLink);
		}
	}

	public static ZDOID GetHolder(Tameable tameable)
	{
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		if (!tameable.m_nview.IsValid())
		{
			return ZDOID.None;
		}
		return tameable.m_nview.GetZDO().GetZDOID(HolderKey);
	}

	public static bool IsLeashed(ZNetView nview)
	{
		//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)
		if (nview.IsValid())
		{
			ZDOID zDOID = nview.GetZDO().GetZDOID(HolderKey);
			return !((ZDOID)(ref zDOID)).IsNone();
		}
		return false;
	}

	public static long GetPost(ZNetView nview)
	{
		if (!nview.IsValid())
		{
			return 0L;
		}
		return nview.GetZDO().GetLong(PostKey, 0L);
	}

	public static bool IsTied(ZNetView nview)
	{
		return GetPost(nview) != 0;
	}

	public static bool IsBound(ZNetView nview)
	{
		if (!IsLeashed(nview))
		{
			return IsTied(nview);
		}
		return true;
	}

	public static bool CanLeash(Tameable tameable, Player player)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		if (tameable.IsTamed() && Object.op_Implicit((Object)(object)tameable.m_monsterAI))
		{
			ZDOID holder = GetHolder(tameable);
			if (((ZDOID)(ref holder)).IsNone())
			{
				string text = tameable.m_nview.GetZDO().GetString(ZDOVars.s_follow, "");
				if (text.Length != 0)
				{
					return text == player.GetPlayerName();
				}
				return true;
			}
		}
		return false;
	}

	public void RequestLeash(Player player)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		m_tameable.m_nview.InvokeRPC("LeashMe_Leash", new object[1] { ((Character)player).GetZDOID() });
	}

	public void RequestRelease()
	{
		m_tameable.m_nview.InvokeRPC("LeashMe_Release", Array.Empty<object>());
	}

	public void RequestOwnership()
	{
		m_tameable.m_nview.InvokeRPC("LeashMe_RequestOwnership", Array.Empty<object>());
	}

	public void RequestTie(long postId)
	{
		m_tameable.m_nview.InvokeRPC("LeashMe_Tie", new object[1] { postId });
	}

	public bool IsInPostReach(HitchingPost post)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		return Vector3.Distance(((Component)post).transform.position, ((Component)this).transform.position) <= 18f;
	}

	public void MoveTo(Vector3 targetPos, Quaternion targetRot)
	{
		//IL_0013: 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_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		ZNetView nview = m_tameable.m_nview;
		ZDO zDO = nview.GetZDO();
		Vector3 exitPosition = GetExitPosition(targetPos, targetRot);
		nview.ResetZDO();
		Object.Destroy((Object)(object)((Component)this).gameObject);
		ZNetScene.instance.m_instances.Remove(zDO);
		zDO.SetPosition(exitPosition);
		zDO.SetRotation(targetRot);
	}

	public void PlaceAt(Vector3 holderPos, Quaternion holderRot)
	{
		//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_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: 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_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = GetExitPosition(holderPos, holderRot);
		float num = default(float);
		if (!ZoneSystem.instance.FindFloor(val, ref num) || num < holderPos.y - 2f)
		{
			val = holderPos + Vector3.up;
		}
		((Component)this).transform.SetPositionAndRotation(val, holderRot);
		Rigidbody val2 = (Object.op_Implicit((Object)(object)m_tameable.m_character) ? m_tameable.m_character.m_body : null);
		if (Object.op_Implicit((Object)(object)val2))
		{
			val2.position = val;
			val2.linearVelocity = Vector3.zero;
		}
	}

	private Vector3 GetExitPosition(Vector3 pos, Quaternion rot)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_004c: Unknown result type (might be due to invalid IL or missing references)
		float num = (Object.op_Implicit((Object)(object)m_tameable.m_character) ? m_tameable.m_character.GetRadius() : 0f);
		return pos + rot * Vector3.forward * (1f + num) + Vector3.up;
	}

	private void Init(Tameable tameable)
	{
		m_tameable = tameable;
		m_hardLimit = ((Utils.GetPrefabName(((Component)this).gameObject) == "Lox") ? 30f : 18f);
		m_tameable.m_nview.Register<ZDOID>("LeashMe_Leash", (Action<long, ZDOID>)RPC_Leash);
		m_tameable.m_nview.Register("LeashMe_Release", (Action<long>)RPC_Release);
		m_tameable.m_nview.Register("LeashMe_RequestOwnership", (Action<long>)RPC_RequestOwnership);
		m_tameable.m_nview.Register<long>("LeashMe_Tie", (Action<long, long>)RPC_Tie);
		s_links.Add(this);
	}

	private void OnDestroy()
	{
		s_links.Remove(this);
	}

	private void RPC_Leash(long sender, ZDOID holder)
	{
		//IL_001d: 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)
		if (!m_tameable.m_nview.IsOwner() || ((ZDOID)(ref holder)).UserID != sender)
		{
			return;
		}
		Player val = FindPlayer(holder);
		if (Object.op_Implicit((Object)(object)val) && CanLeash(m_tameable, val))
		{
			ZDO zDO = m_tameable.m_nview.GetZDO();
			if (IsTied(m_tameable.m_nview))
			{
				zDO.Set(PostKey, 0L);
				m_tameable.m_monsterAI.SetFollowTarget((GameObject)null);
			}
			zDO.Set(HolderKey, holder);
			if (m_tameable.m_nview.GetZDO().GetString(ZDOVars.s_follow, "").Length == 0)
			{
				m_tameable.Command((Humanoid)(object)val, false);
			}
		}
	}

	private void RPC_Release(long sender)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		if (m_tameable.m_nview.IsOwner())
		{
			ZDOID holder = GetHolder(m_tameable);
			if (((ZDOID)(ref holder)).UserID == sender)
			{
				Release();
			}
		}
	}

	private void RPC_Tie(long sender, long postId)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
		ZDOID holder = GetHolder(m_tameable);
		if (m_tameable.m_nview.IsOwner() && !((ZDOID)(ref holder)).IsNone() && ((ZDOID)(ref holder)).UserID == sender && Object.op_Implicit((Object)(object)m_tameable.m_monsterAI))
		{
			HitchingPost hitchingPost = HitchingPost.Find(postId);
			if (Object.op_Implicit((Object)(object)hitchingPost) && IsInPostReach(hitchingPost))
			{
				ZDO zDO = m_tameable.m_nview.GetZDO();
				zDO.Set(HolderKey, ZDOID.None);
				zDO.Set(PostKey, postId);
				zDO.Set(PostPosKey, ((Component)hitchingPost).transform.position);
				zDO.Set(ZDOVars.s_follow, "");
				m_tameable.m_monsterAI.SetFollowTarget(((Component)hitchingPost).gameObject);
				((BaseAI)m_tameable.m_monsterAI).SetPatrolPoint(((Component)hitchingPost).transform.position);
				m_invalidSince = -1f;
			}
		}
	}

	private void RPC_RequestOwnership(long sender)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		if (m_tameable.m_nview.IsOwner())
		{
			ZDOID holder = GetHolder(m_tameable);
			if (((ZDOID)(ref holder)).UserID == sender)
			{
				m_tameable.m_nview.GetZDO().SetOwner(sender);
			}
		}
	}

	private void Release()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		ZDO zDO = m_tameable.m_nview.GetZDO();
		zDO.Set(HolderKey, ZDOID.None);
		zDO.Set(PostKey, 0L);
		m_tameable.m_monsterAI.SetFollowTarget((GameObject)null);
		((BaseAI)m_tameable.m_monsterAI).SetPatrolPoint();
		zDO.Set(ZDOVars.s_follow, "");
		m_invalidSince = -1f;
	}

	private void Update()
	{
		//IL_00b1: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		if (Time.time < m_nextCheck || !m_tameable.m_nview.IsValid() || !m_tameable.m_nview.IsOwner())
		{
			return;
		}
		m_nextCheck = Time.time + 1f;
		long post = GetPost(m_tameable.m_nview);
		if (post != 0L)
		{
			CheckPost(post);
			return;
		}
		GameObject val = (Object.op_Implicit((Object)(object)m_tameable.m_monsterAI) ? m_tameable.m_monsterAI.GetFollowTarget() : null);
		if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.GetComponent<HitchingPost>()))
		{
			m_tameable.m_monsterAI.SetFollowTarget((GameObject)null);
		}
		ZDOID holder = GetHolder(m_tameable);
		Player val2 = (((ZDOID)(ref holder)).IsNone() ? null : FindPlayer(holder));
		if (Object.op_Implicit((Object)(object)val2) && !LeashPortal.IsLanding(val2) && Vector3.Distance(((Component)val2).transform.position, ((Component)this).transform.position) > m_hardLimit)
		{
			Release();
		}
		else if (((ZDOID)(ref holder)).IsNone() || IsHolderValid(val2))
		{
			m_invalidSince = -1f;
		}
		else
		{
			ReleaseAfterGrace();
		}
	}

	private void CheckPost(long postId)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		Vector3 vec = m_tameable.m_nview.GetZDO().GetVec3(PostPosKey, ((Component)this).transform.position);
		HitchingPost hitchingPost = HitchingPost.Find(postId);
		if (Object.op_Implicit((Object)(object)hitchingPost))
		{
			if (!IsInPostReach(hitchingPost))
			{
				Release();
				return;
			}
			if (Object.op_Implicit((Object)(object)m_tameable.m_monsterAI) && (Object)(object)m_tameable.m_monsterAI.GetFollowTarget() != (Object)(object)((Component)hitchingPost).gameObject)
			{
				m_tameable.m_monsterAI.SetFollowTarget(((Component)hitchingPost).gameObject);
			}
			m_invalidSince = -1f;
		}
		else if (!ZNetScene.instance.IsAreaReady(vec))
		{
			float num = (Object.op_Implicit((Object)(object)m_tameable.m_monsterAI) ? (2f * ((BaseAI)m_tameable.m_monsterAI).m_randomMoveRange) : 0f);
			if (Vector3.Distance(vec, ((Component)this).transform.position) > 18f + num)
			{
				Release();
			}
			else
			{
				m_invalidSince = -1f;
			}
		}
		else
		{
			ReleaseAfterGrace();
		}
	}

	private void ReleaseAfterGrace()
	{
		if (m_invalidSince < 0f)
		{
			m_invalidSince = Time.time;
		}
		else if (Time.time - m_invalidSince >= 3f)
		{
			Release();
		}
	}

	private static bool IsHolderValid(Player player)
	{
		if (Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead())
		{
			return LeashItem.IsHeld(((Character)player).m_nview.GetZDO());
		}
		return false;
	}

	private static Player FindPlayer(ZDOID id)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = ZNetScene.instance.FindInstance(id);
		if (!Object.op_Implicit((Object)(object)val))
		{
			return null;
		}
		return val.GetComponent<Player>();
	}
}
[BepInPlugin("de.evabs.valheim.leashme", "LeashMe", "1.3.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
internal class LeashMe : BaseUnityPlugin
{
	public const string PluginGUID = "de.evabs.valheim.leashme";

	public const string PluginName = "LeashMe";

	public const string PluginVersion = "1.3.1";

	public static CustomLocalization Localization = LocalizationManager.Instance.GetLocalization();

	private void Awake()
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		AddTranslations();
		LeashItem.Register();
		PackSaddleItem.Register();
		PackSaddleCrate.Register();
		HitchingPostPiece.Register();
		new Harmony("de.evabs.valheim.leashme").PatchAll(typeof(LeashPatches).Assembly);
	}

	private void Update()
	{
		LocalLeash.Update();
		TamePins.Update();
	}

	private static void AddTranslations()
	{
		CustomLocalization localization = Localization;
		string text = "English";
		localization.AddTranslation(ref text, new Dictionary<string, string>
		{
			{ "leashme_leash", "Leash" },
			{ "leashme_leash_desc", "Equip in the off-hand to lead tamed animals." },
			{ "leashme_attach", "Leash" },
			{ "leashme_detach", "Unleash" },
			{ "leashme_too_weak", "This animal needs a stronger leash" },
			{ "leashme_limit", "You can't lead more than 5 animals." },
			{ "leashme_lost", "$1 is no longer leashed." },
			{ "leashme_lost_many", "$1 animals are no longer leashed." },
			{ "leashme_portal_too_big", "A leashed animal is too big for this portal." },
			{ "leashme_packsaddle", "Pack saddle" },
			{ "leashme_packsaddle_desc", "Use on a Lox to transport cargo. The cargo can only be accessed by the person who put the saddle on." },
			{ "leashme_packsaddle_ready", "is ready to carry cargo." },
			{ "leashme_post", "Weak Hitching Post" },
			{ "leashme_post_silver", "Hitching Post" },
			{ "leashme_post_blackmetal", "Strong Hitching Post" },
			{ "leashme_post_desc", "Tie up leashed animals here." },
			{ "leashme_tie", "Tie up" },
			{ "leashme_untie", "Untie all" },
			{ "leashme_post_too_weak", "$1 needs a stronger hitching post" },
			{ "leashme_post_too_weak_many", "$1 animals need a stronger hitching post" },
			{ "leashme_post_too_far", "$1 is too far away to be hitched to the post" },
			{ "leashme_post_too_far_many", "$1 animals are too far away to be hitched to the post" },
			{ "leashme_post_no_room", "There was no room for 1 animal" },
			{ "leashme_post_no_room_many", "There was no room for $1 animals" }
		});
		CustomLocalization localization2 = Localization;
		text = "German";
		localization2.AddTranslation(ref text, new Dictionary<string, string>
		{
			{ "leashme_leash", "Leine" },
			{ "leashme_leash_desc", "In der Nebenhand ausrüsten, um gezähmte Tiere zu führen." },
			{ "leashme_attach", "Anleinen" },
			{ "leashme_detach", "Ableinen" },
			{ "leashme_too_weak", "Dieses Tier braucht eine stärkere Leine" },
			{ "leashme_limit", "Du kannst nicht mehr als 5 Tiere führen." },
			{ "leashme_lost", "$1 ist nicht mehr angeleint." },
			{ "leashme_lost_many", "$1 Tiere sind nicht mehr angeleint." },
			{ "leashme_portal_too_big", "Ein angeleintes Tier ist zu groß für dieses Portal." },
			{ "leashme_packsaddle", "Packsattel" },
			{ "leashme_packsaddle_desc", "Auf einen Lox anwenden, um Fracht zu transportieren. Nur wer den Sattel angelegt hat, kommt an die Fracht." },
			{ "leashme_packsaddle_ready", "ist bereit, Fracht zu tragen." },
			{ "leashme_post", "Schwacher Anbindepfosten" },
			{ "leashme_post_silver", "Anbindepfosten" },
			{ "leashme_post_blackmetal", "Starker Anbindepfosten" },
			{ "leashme_post_desc", "Hier angeleinte Tiere anbinden." },
			{ "leashme_tie", "Anbinden" },
			{ "leashme_untie", "Alle losmachen" },
			{ "leashme_post_too_weak", "$1 braucht einen stärkeren Anbindepfosten" },
			{ "leashme_post_too_weak_many", "$1 Tiere brauchen einen stärkeren Anbindepfosten" },
			{ "leashme_post_too_far", "$1 ist zu weit weg, um am Pfosten angebunden zu werden" },
			{ "leashme_post_too_far_many", "$1 Tiere sind zu weit weg, um am Pfosten angebunden zu werden" },
			{ "leashme_post_no_room", "Für 1 Tier war kein Platz mehr" },
			{ "leashme_post_no_room_many", "Für $1 Tiere war kein Platz mehr" }
		});
	}
}
internal static class LeashPatches
{
	[HarmonyPatch(typeof(Tameable), "Awake")]
	private static class TameableAwake
	{
		private static void Postfix(Tameable __instance)
		{
			LeashLink.Attach(__instance);
			PackSaddle.Attach(__instance);
		}
	}

	[HarmonyPatch(typeof(Tameable), "UseItem")]
	private static class TameableUseItem
	{
		private static bool Prefix(Tameable __instance, Humanoid user, ItemData item, ref bool __result)
		{
			if (__instance.m_nview.IsValid())
			{
				return !PackSaddle.TryUseItem(__instance, user, item, ref __result);
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(Tameable), "RPC_AddSaddle")]
	private static class TameableRpcAddSaddle
	{
		private static bool Prefix(Tameable __instance)
		{
			return PackSaddle.GetOwner(__instance.m_nview) == 0;
		}
	}

	[HarmonyPatch(typeof(Container), "CheckAccess")]
	private static class ContainerCheckAccess
	{
		private static bool Prefix(Container __instance, long playerID, ref bool __result)
		{
			return !PackSaddle.TryCheckAccess(__instance, playerID, ref __result);
		}
	}

	[HarmonyPatch(typeof(Tameable), "Interact")]
	private static class TameableInteract
	{
		private static bool Prefix(Tameable __instance, Humanoid user, bool hold, ref bool __result)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			LeashLink component = ((Component)__instance).GetComponent<LeashLink>();
			if (!LocalHasLeash(user) || !__instance.IsTamed() || !Object.op_Implicit((Object)(object)component))
			{
				return true;
			}
			__result = false;
			if (hold)
			{
				return false;
			}
			Player val = (Player)user;
			if (LeashLink.GetHolder(__instance) == ((Character)val).GetZDOID())
			{
				LocalLeash.Release(component);
				__result = true;
			}
			else if (LeashLink.CanLeash(__instance, val) && LeashItem.IsStrongEnough((Humanoid)(object)val, __instance))
			{
				if (LocalLeash.IsAtLimit(component))
				{
					((Character)val).Message((MessageType)2, "$leashme_limit", 0, (Sprite)null, false);
					return false;
				}
				LocalLeash.Leash(component, val);
				__result = true;
			}
			return false;
		}
	}

	[HarmonyPatch(typeof(Tameable), "GetHoverText")]
	private static class TameableHoverText
	{
		private static bool Prefix(Tameable __instance, ref string __result)
		{
			//IL_0071: 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)
			if (!LocalHasLeash((Humanoid)(object)Player.m_localPlayer) || !__instance.IsTamed() || !__instance.m_nview.IsValid() || !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<LeashLink>()))
			{
				return true;
			}
			string text = __instance.GetName();
			if (Object.op_Implicit((Object)(object)__instance.m_character))
			{
				text += Localization.instance.Localize(" ( $hud_tame, " + __instance.GetStatusString() + " )");
			}
			Player localPlayer = Player.m_localPlayer;
			if (LeashLink.GetHolder(__instance) == ((Character)localPlayer).GetZDOID())
			{
				text += Localization.instance.Localize("\n[<color=yellow><b>$KEY_Use</b></color>] $leashme_detach");
			}
			else if (LeashLink.CanLeash(__instance, localPlayer))
			{
				text += Localization.instance.Localize(LeashItem.IsStrongEnough((Humanoid)(object)localPlayer, __instance) ? "\n[<color=yellow><b>$KEY_Use</b></color>] $leashme_attach" : "\n$leashme_too_weak");
			}
			__result = text;
			return false;
		}
	}

	[HarmonyPatch(typeof(Sadle), "Interact")]
	private static class SadleInteract
	{
		private static bool Prefix(Sadle __instance, Humanoid character, bool repeat, bool alt, ref bool __result)
		{
			Tameable linkedTameable = GetLinkedTameable(__instance);
			if (!Object.op_Implicit((Object)(object)linkedTameable) || alt || (!LocalHasLeash(character) && !LeashLink.IsTied(linkedTameable.m_nview)))
			{
				return true;
			}
			__result = linkedTameable.Interact(character, repeat, alt);
			return false;
		}
	}

	[HarmonyPatch(typeof(Sadle), "GetHoverText")]
	private static class SadleHoverText
	{
		private static bool Prefix(Sadle __instance, ref string __result)
		{
			Tameable linkedTameable = GetLinkedTameable(__instance);
			if (!Object.op_Implicit((Object)(object)linkedTameable))
			{
				return true;
			}
			bool flag = LocalHasLeash((Humanoid)(object)Player.m_localPlayer);
			if (!flag && (!LeashLink.IsTied(linkedTameable.m_nview) || !__instance.InUseDistance((Humanoid)(object)Player.m_localPlayer)))
			{
				return true;
			}
			string text = (flag ? linkedTameable.GetHoverText() : Localization.instance.Localize(__instance.m_hoverText + "\n[<color=yellow><b>$KEY_Use</b></color>] $hud_pet"));
			if (__instance.InUseDistance((Humanoid)(object)Player.m_localPlayer))
			{
				text += Localization.instance.Localize((ZInput.IsNonClassicFunctionality() && ZInput.IsGamepadActive()) ? "\n[<color=yellow><b>$KEY_AltKeys + $KEY_Use</b></color>] $hud_saddle_remove" : "\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] $hud_saddle_remove");
			}
			__result = text;
			return false;
		}
	}

	[HarmonyPatch(typeof(Tameable), "RPC_Command")]
	private static class TameableRpcCommand
	{
		private static bool Prefix(Tameable __instance, ZDOID characterID)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (LeashLink.IsTied(__instance.m_nview))
			{
				return false;
			}
			ZDOID holder = LeashLink.GetHolder(__instance);
			if (!((ZDOID)(ref holder)).IsNone())
			{
				if (holder == characterID)
				{
					return !Object.op_Implicit((Object)(object)__instance.m_monsterAI.GetFollowTarget());
				}
				return false;
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(Humanoid), "HideHandItems")]
	private static class HumanoidHideHandItems
	{
		private static void Prefix(Humanoid __instance, bool onlyRightHand)
		{
			if (!onlyRightHand && LocalHasLeash(__instance) && IsManualHideInput(__instance))
			{
				LocalLeash.ReleaseAll();
			}
		}

		private static bool IsManualHideInput(Humanoid player)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			bool flag = !Hud.InRadial() && ZInput.GetButtonUp("JoyHide") && ZInput.GetButtonLastPressedTimer("JoyHide") < 0.33f && !ZInput.GetButton("JoyAltKeys") && !((Character)player).InPlaceMode();
			if ((int)ZInput.InputLayout != 0 && ZInput.IsGamepadActive())
			{
				return flag;
			}
			return ZInput.GetButtonDown("Hide") || flag;
		}
	}

	[HarmonyPatch(typeof(Humanoid), "GetCurrentBlocker")]
	private static class HumanoidCurrentBlocker
	{
		private static bool Prefix(Humanoid __instance, ref ItemData __result)
		{
			if (!LeashItem.IsEquipped(__instance))
			{
				return true;
			}
			__result = __instance.GetCurrentWeapon();
			return false;
		}
	}

	[HarmonyPatch(typeof(Humanoid), "SetupAnimationState")]
	private static class HumanoidSetupAnimationState
	{
		private static bool Prefix(Humanoid __instance)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (!LeashItem.IsEquipped(__instance))
			{
				return true;
			}
			ItemData val = __instance.m_rightItem ?? (Object.op_Implicit((Object)(object)__instance.m_unarmedWeapon) ? __instance.m_unarmedWeapon.m_itemData : null);
			if (val != null)
			{
				__instance.SetAnimationState(val.m_shared.m_animationState);
			}
			return false;
		}
	}

	[HarmonyPatch(typeof(Player), "SetControls")]
	private static class PlayerSetControls
	{
		private static Player s_player;

		private static Vector3 s_unlimited;

		private static void Prefix(Player __instance)
		{
			//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)
			if ((Object)(object)__instance == (Object)(object)s_player)
			{
				((Character)__instance).m_moveDir = s_unlimited;
			}
		}

		private static void Postfix(Player __instance)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			Vector3 moveDir = ((Character)__instance).m_moveDir;
			Vector3 val = LocalLeash.LimitMove(__instance, moveDir);
			s_player = ((val != moveDir) ? __instance : null);
			s_unlimited = moveDir;
			((Character)__instance).m_moveDir = val;
		}
	}

	[HarmonyPatch(typeof(Player), "Dodge")]
	private static class PlayerDodge
	{
		private static bool Prefix(Player __instance, ref Vector3 dodgeDir)
		{
			//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_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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = LocalLeash.LimitMove(__instance, dodgeDir);
			if (val == dodgeDir)
			{
				return true;
			}
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				return false;
			}
			dodgeDir = ((Vector3)(ref val)).normalized;
			return true;
		}
	}

	[HarmonyPatch(typeof(TeleportWorld), "Teleport")]
	private static class TeleportWorldTeleport
	{
		private static void Prefix(TeleportWorld __instance)
		{
			LeashPortal.CurrentPortal = __instance;
		}

		private static void Finalizer()
		{
			LeashPortal.CurrentPortal = null;
		}
	}

	[HarmonyPatch(typeof(Player), "TeleportTo")]
	private static class PlayerTeleportTo
	{
		private static bool Prefix(Player __instance, ref bool __result)
		{
			TeleportWorld currentPortal = LeashPortal.CurrentPortal;
			if (!Object.op_Implicit((Object)(object)currentPortal) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || ((Character)__instance).IsTeleporting() || !LeashPortal.IsBlocked(currentPortal))
			{
				return true;
			}
			((Character)__instance).Message((MessageType)2, "$leashme_portal_too_big", 0, (Sprite)null, false);
			__result = false;
			return false;
		}

		private static void Postfix(Player __instance, bool __result)
		{
			if (__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				LeashPortal.OnTeleportStarted(Object.op_Implicit((Object)(object)LeashPortal.CurrentPortal));
			}
		}
	}

	[HarmonyPatch(typeof(Player), "UpdateTeleport")]
	private static class PlayerUpdateTeleport
	{
		private static void Postfix(Player __instance)
		{
			LeashPortal.OnUpdateTeleport(__instance);
		}
	}

	[HarmonyPatch(typeof(ArmorStand), "CanAttach")]
	private static class ArmorStandCanAttach
	{
		private static bool Prefix(ItemData item, ref bool __result)
		{
			if (!LeashItem.IsLeash(item) && !PackSaddleItem.IsPackSaddle(item))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}

	[HarmonyPatch(typeof(ItemStand), "CanAttach")]
	private static class ItemStandCanAttach
	{
		private static bool Prefix(ItemStand __instance, ItemData item, ref bool __result)
		{
			if (!PackSaddleItem.IsPackSaddle(item) || !LeashItem.IsWallStand(__instance))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}

	[HarmonyPatch(typeof(ItemStand), "SetVisualItem")]
	private static class ItemStandSetVisualItem
	{
		private static void Prefix(ItemStand __instance, out GameObject __state)
		{
			__state = __instance.m_visualItem;
		}

		private static void Postfix(ItemStand __instance, int itemHash, GameObject __state)
		{
			if ((Object)(object)__instance.m_visualItem != (Object)(object)__state)
			{
				LeashItem.OnStandVisual(__instance, itemHash);
			}
		}
	}

	[HarmonyPatch(typeof(Requirement), "GetAmount")]
	private static class RequirementGetAmount
	{
		private static bool Prefix(Requirement __instance, int qualityLevel, ref int __result)
		{
			return !LeashItem.TryGetAmount(__instance, qualityLevel, out __result);
		}
	}

	[HarmonyPatch(typeof(Minimap), "Start")]
	private static class MinimapStart
	{
		private static void Postfix(Minimap __instance)
		{
			PawMarker.Register(__instance);
			PlayerMarkerOrder.Apply(__instance);
		}
	}

	[HarmonyPatch(typeof(Minimap), "GetSprite")]
	private static class MinimapGetSprite
	{
		private static bool Prefix(PinType type, ref Sprite __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (type != PawMarker.PawType)
			{
				return true;
			}
			__result = PawMarker.GetIcon();
			return false;
		}
	}

	[HarmonyPatch(typeof(MonsterAI), "UpdateTarget")]
	private static class MonsterAIUpdateTarget
	{
		private static void Postfix(MonsterAI __instance, ref bool canHearTarget, ref bool canSeeTarget)
		{
			if (LeashLink.IsBound(((BaseAI)__instance).m_nview))
			{
				__instance.m_targetCreature = null;
				__instance.m_targetStatic = null;
				__instance.m_timeSinceAttacking = 0f;
				canHearTarget = false;
				canSeeTarget = false;
			}
		}
	}

	[HarmonyPatch(typeof(BaseAI), "Follow")]
	private static class BaseAIFollow
	{
		private const float VanillaStopDistance = 3f;

		private static bool Prefix(BaseAI __instance, GameObject go)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (!LeashLink.IsBound(__instance.m_nview))
			{
				return true;
			}
			float num = 3f + __instance.m_character.GetRadius();
			if (Vector3.Distance(go.transform.position, ((Component)__instance).transform.position) >= num)
			{
				return true;
			}
			__instance.StopMoving();
			return false;
		}
	}

	private static bool LocalHasLeash(Humanoid user)
	{
		if (Object.op_Implicit((Object)(object)user) && (Object)(object)user == (Object)(object)Player.m_localPlayer)
		{
			return LeashItem.IsEquipped(user);
		}
		return false;
	}

	private static Tameable GetLinkedTameable(Sadle sadle)
	{
		Tameable tameable = sadle.GetTameable();
		if (!Object.op_Implicit((Object)(object)tameable) || !Object.op_Implicit((Object)(object)((Component)tameable).GetComponent<LeashLink>()))
		{
			return null;
		}
		return tameable;
	}
}
internal static class LeashPortal
{
	private const string SmallPortal = "portal_wood";

	private static readonly HashSet<string> LargeCreatures = new HashSet<string> { "Lox", "Asksvin", "Moose" };

	private const float JumpTime = 2f;

	private static readonly List<LeashLink> s_links = new List<LeashLink>();

	public static TeleportWorld CurrentPortal;

	private static bool s_transportPending;

	private static bool s_arrivalPending;

	public static bool IsBlocked(TeleportWorld portal)
	{
		if (Utils.GetPrefabName(((Component)portal).gameObject) != "portal_wood")
		{
			return false;
		}
		LocalLeash.GetLinks(s_links, confirmedOnly: false);
		foreach (LeashLink s_link in s_links)
		{
			if (LargeCreatures.Contains(Utils.GetPrefabName(((Component)s_link).gameObject)))
			{
				return true;
			}
		}
		return false;
	}

	public static void OnTeleportStarted(bool viaPortal)
	{
		s_transportPending = viaPortal;
		s_arrivalPending = false;
		if (!viaPortal)
		{
			return;
		}
		LocalLeash.GetLinks(s_links, confirmedOnly: true);
		foreach (LeashLink s_link in s_links)
		{
			s_link.RequestOwnership();
		}
	}

	public static bool IsLanding(Player holder)
	{
		if (s_arrivalPending && (Object)(object)holder == (Object)(object)Player.m_localPlayer)
		{
			return holder.m_teleporting;
		}
		return false;
	}

	public static void OnUpdateTeleport(Player player)
	{
		//IL_005c: 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_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)player != (Object)(object)Player.m_localPlayer)
		{
			return;
		}
		if (s_arrivalPending && !player.m_teleporting)
		{
			s_arrivalPending = false;
			LocalLeash.GetLinks(s_links, confirmedOnly: true);
			foreach (LeashLink s_link in s_links)
			{
				if (s_link.Tameable.m_nview.IsOwner())
				{
					s_link.PlaceAt(((Component)player).transform.position, ((Component)player).transform.rotation);
				}
			}
		}
		if (!s_transportPending || !player.m_teleporting || player.m_teleportTimer <= 2f)
		{
			return;
		}
		s_transportPending = false;
		s_arrivalPending = true;
		LocalLeash.GetLinks(s_links, confirmedOnly: true);
		foreach (LeashLink s_link2 in s_links)
		{
			if (s_link2.Tameable.m_nview.IsOwner())
			{
				s_link2.MoveTo(player.m_teleportTargetPos, player.m_teleportTargetRot);
			}
			else
			{
				LocalLeash.ReleaseLost(s_link2);
			}
		}
	}
}
internal static class LocalLeash
{
	private class Handle
	{
		public LeashLink Link;

		public float RequestedAt;

		public bool Confirmed;
	}

	private const int MaxLinks = 5;

	private const float PendingTimeout = 5f;

	private const float SoftLimit = 12f;

	private const float LostMessageSeconds = 4f;

	private static readonly List<Handle> s_handles = new List<Handle>();

	private static readonly List<Vector3> s_aways = new List<Vector3>();

	private static int s_lostCount;

	private static float s_lostAt = float.MinValue;

	public static bool IsAtLimit(LeashLink link)
	{
		if (Find(link) == null)
		{
			return s_handles.Count >= 5;
		}
		return false;
	}

	public static Vector3 LimitMove(Player player, Vector3 dir)
	{
		//IL_000d: 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_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: 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_00af: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: 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_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: 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_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)player != (Object)(object)Player.m_localPlayer)
		{
			return dir;
		}
		List<Vector3> list = s_aways;
		list.Clear();
		foreach (Handle s_handle in s_handles)
		{
			if (s_handle.Confirmed && Object.op_Implicit((Object)(object)s_handle.Link))
			{
				Vector3 val = ((Component)player).transform.position - ((Component)s_handle.Link).transform.position;
				if (((Vector3)(ref val)).magnitude >= 12f)
				{
					val.y = 0f;
					list.Add(((Vector3)(ref val)).normalized);
				}
			}
		}
		if (list.Count == 0 || IsAllowed(dir, list))
		{
			return dir;
		}
		Vector3 result = Vector3.zero;
		foreach (Vector3 item in list)
		{
			Vector3 val2 = dir - item * Vector3.Dot(dir, item);
			if (((Vector3)(ref val2)).sqrMagnitude > ((Vector3)(ref result)).sqrMagnitude && IsAllowed(val2, list))
			{
				result = val2;
			}
		}
		return result;
	}

	private static bool IsAllowed(Vector3 dir, List<Vector3> aways)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		foreach (Vector3 away in aways)
		{
			if (Vector3.Dot(dir, away) > 0.001f)
			{
				return false;
			}
		}
		return true;
	}

	public static void Leash(LeashLink link, Player player)
	{
		Handle handle = Find(link);
		if (handle == null)
		{
			handle = new Handle
			{
				Link = link
			};
			s_handles.Add(handle);
		}
		handle.RequestedAt = Time.time;
		handle.Confirmed = false;
		link.RequestLeash(player);
	}

	public static void Release(LeashLink link)
	{
		link.RequestRelease();
		Handle handle = Find(link);
		if (handle != null)
		{
			if (handle.Confirmed)
			{
				PlaySound(Player.m_localPlayer);
			}
			s_handles.Remove(handle);
		}
	}

	public static void ReleaseAll()
	{
		for (int num = s_handles.Count - 1; num >= 0; num--)
		{
			LeashLink link = s_handles[num].Link;
			if (Object.op_Implicit((Object)(object)link))
			{
				Release(link);
			}
			else
			{
				s_handles.RemoveAt(num);
			}
		}
	}

	public static void ReleaseLost(LeashLink link)
	{
		Release(link);
		if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
		{
			ShowLost(Player.m_localPlayer, link.Tameable.GetHoverName());
		}
	}

	public static void GetLinks(List<LeashLink> result, bool confirmedOnly)
	{
		result.Clear();
		foreach (Handle s_handle in s_handles)
		{
			if (Object.op_Implicit((Object)(object)s_handle.Link) && s_handle.Link.Tameable.m_nview.IsValid() && (s_handle.Confirmed || !confirmedOnly))
			{
				result.Add(s_handle.Link);
			}
		}
	}

	public static void Adopt(LeashLink link)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if (Object.op_Implicit((Object)(object)localPlayer) && Find(link) == null && !(LeashLink.GetHolder(link.Tameable) != ((Character)localPlayer).GetZDOID()))
		{
			s_handles.RemoveAll((Handle h) => !Object.op_Implicit((Object)(object)h.Link) || !h.Link.Tameable.m_nview.IsValid());
			s_handles.Add(new Handle
			{
				Link = link,
				RequestedAt = Time.time,
				Confirmed = true
			});
		}
	}

	private static Handle Find(LeashLink link)
	{
		foreach (Handle s_handle in s_handles)
		{
			if ((Object)(object)s_handle.Link == (Object)(object)link)
			{
				return s_handle;
			}
		}
		return null;
	}

	private static void ShowLost(Player player, string name)
	{
		s_lostCount = ((Time.time - s_lostAt > 4f) ? 1 : (s_lostCount + 1));
		s_lostAt = Time.time;
		string text = ((s_lostCount == 1) ? Localization.instance.Localize("$leashme_lost", new string[1] { name }) : Localization.instance.Localize("$leashme_lost_many", new string[1] { s_lostCount.ToString() }));
		((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false);
	}

	private static void PlaySound(Player player)
	{
		//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_0026: Unknown result type (might be due to invalid IL or missing references)
		if (Object.op_Implicit((Object)(object)player))
		{
			((Humanoid)player).m_pickupEffects.Create(((Component)player).transform.position, Quaternion.identity, (Transform)null, 1f, -1, ((Character)player).GetZDOID());
		}
	}

	public static void Update()
	{
		//IL_0085: 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)
		if (s_handles.Count == 0)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if (!Object.op_Implicit((Object)(object)localPlayer))
		{
			s_handles.Clear();
			return;
		}
		bool flag = false;
		for (int num = s_handles.Count - 1; num >= 0; num--)
		{
			Handle handle = s_handles[num];
			if (!Object.op_Implicit((Object)(object)handle.Link) || !handle.Link.Tameable.m_nview.IsValid())
			{
				s_handles.RemoveAt(num);
			}
			else if (LeashLink.GetHolder(handle.Link.Tameable) == ((Character)localPlayer).GetZDOID())
			{
				if (!handle.Confirmed)
				{
					handle.Confirmed = true;
					PlaySound(localPlayer);
				}
				flag = true;
			}
			else if (handle.Confirmed)
			{
				s_handles.RemoveAt(num);
				if (!LeashLink.IsTied(handle.Link.Tameable.m_nview))
				{
					ShowLost(localPlayer, handle.Link.Tameable.GetHoverName());
				}
				PlaySound(localPlayer);
			}
			else if (Time.time - handle.RequestedAt > 5f)
			{
				Release(handle.Link);
			}
		}
		if (flag)
		{
			if (!LeashItem.IsHeld((Humanoid)(object)localPlayer) || ((Character)localPlayer).IsDead())
			{
				ReleaseAll();
			}
			else if (!LeashItem.IsEquipped((Humanoid)(object)localPlayer) && IsAutoHideOver(localPlayer))
			{
				((Humanoid)localPlayer).ShowHandItems(false, true);
			}
		}
	}

	private static bool IsAutoHideOver(Player player)
	{
		if (!((Character)player).IsSwimming() && !((Character)player).IsAttached() && !Object.op_Implicit((Object)(object)player.GetCurrentCraftingStation()) && ((Character)player).TakeInput() && !((Character)player).InAttack())
		{
			return !((Character)player).InDodge();
		}
		return false;
	}
}
internal class MaterialTestCommand : ConsoleCommand
{
	private static readonly string[] Placeholders = new string[4] { "crate_wood", "linen", "linen_dark", "leash_leather" };

	private static readonly Dictionary<Material, Material> Backups = new Dictionary<Material, Material>();

	public override string Name => "leashme_mat";

	public override string Help => "leashme_mat <placeholder> <prefab> [material] | <placeholder> reset";

	public static void Register()
	{
		CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new MaterialTestCommand());
	}

	public override void Run(string[] args)
	{
		//IL_031a: Unknown result type (might be due to invalid IL or missing references)
		//IL_058f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0594: Unknown result type (might be due to invalid IL or missing references)
		//IL_05b0: Expected O, but got Unknown
		if (args.Length == 0)
		{
			Print("Placeholders: " + string.Join(", ", Placeholders));
			return;
		}
		if (args[0] == "find" && args.Length == 2)
		{
			List<string> list = (from m in Resources.FindObjectsOfTypeAll<Material>()
				where ((Object)m).name.IndexOf(args[1], StringComparison.OrdinalIgnoreCase) >= 0
				group m by ((Object)m).name + " [" + ((Object)m.shader).name + "]" into g
				select $"{g.Key} x{g.Count()}").ToList();
			Console instance = Console.instance;
			if (instance != null)
			{
				((Terminal)instance).AddString($"find {args[1]}: {list.Count} materials, see BepInEx log.");
			}
			Logger.LogInfo((object)("find " + args[1] + ": " + string.Join(", ", list)));
			return;
		}
		List<Material> list2 = (from m in Resources.FindObjectsOfTypeAll<Material>()
			where ((Object)m).name == args[0] || ((Object)m).name.StartsWith(args[0] + " ")
			where !Backups.ContainsValue(m)
			select m).ToList();
		if (list2.Count == 0)
		{
			Print("No loaded material '" + args[0] + "'.");
			return;
		}
		if (args.Length == 4 && args[1] == "set")
		{
			if (!float.TryParse(args[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				Print("Not a number: '" + args[3] + "'.");
				return;
			}
			foreach (Material item in list2)
			{
				item.SetFloat(args[2], result);
			}
			Print($"{args[0]}: {args[2]} = {result} ({list2.Count} materials, property known: {list2[0].HasProperty(args[2])}).");
			return;
		}
		if (args.Length == 5 && args[1] == "color")
		{
			float[] array = new float[3];
			for (int num = 0; num < 3; num++)
			{
				if (!float.TryParse(args[2 + num], NumberStyles.Float, CultureInfo.InvariantCulture, out array[num]))
				{
					Print("Not a number: '" + args[2 + num] + "'.");
					return;
				}
			}
			foreach (Material item2 in list2)
			{
				item2.SetColor("_Color", new Color(array[0], array[1], array[2], 1f));
			}
			Print($"{args[0]}: _Color = {array[0]} {array[1]} {array[2]} ({list2.Count} materials).");
			return;
		}
		if (args.Length == 2 && args[1] == "reset")
		{
			foreach (Material item3 in list2.Where(Backups.ContainsKey))
			{
				Copy(Backups[item3], item3);
			}
			Print($"{args[0]}: reset ({list2.Count} materials).");
			return;
		}
		if (args.Length < 2)
		{
			Print(((ConsoleCommand)this).Help);
			return;
		}
		GameObject prefab = PrefabManager.Instance.GetPrefab(args[1]);
		if (!Object.op_Implicit((Object)(object)prefab))
		{
			Print("No prefab '" + args[1] + "'.");
			return;
		}
		List<Material> source = (from m in prefab.GetComponentsInChildren<Renderer>(true).SelectMany((Renderer r) => r.sharedMaterials)
			where Object.op_Implicit((Object)(object)m)
			select m).Distinct().ToList();
		if (args.Length == 2)
		{
			Print(args[1] + ": " + string.Join(", ", source.Select((Material m) => ((Object)m).name + " [" + ((Object)m.shader).name + "]")));
			return;
		}
		Material val = ((IEnumerable<Material>)source).FirstOrDefault((Func<Material, bool>)((Material m) => ((Object)m).name == args[2]));
		if (!Object.op_Implicit((Object)(object)val))
		{
			Print(args[1] + " has no material '" + args[2] + "'.");
			return;
		}
		foreach (Material item4 in list2)
		{
			if (!Backups.ContainsKey(item4))
			{
				Backups[item4] = new Material(item4)
				{
					name = ((Object)item4).name + "_backup"
				};
			}
			Copy(val, item4);
		}
		Print($"{args[0]}: {args[1]}/{args[2]} [{((Object)val.shader).name}] ({list2.Count} materials).");
	}

	private static void Print(string text)
	{
		Console instance = Console.instance;
		if (instance != null)
		{
			((Terminal)instance).AddString(text);
		}
		Logger.LogInfo((object)text);
	}

	private static void Copy(Material source, Material target)
	{
		string name = ((Object)target).name;
		target.shader = source.shader;
		target.CopyPropertiesFromMaterial(source);
		target.shaderKeywords = source.shaderKeywords;
		target.renderQueue = source.renderQueue;
		((Object)target).name = name;
	}
}
internal class PackSaddle : MonoBehaviour
{
	private const string LoxPrefabName = "Lox";

	private const string BundleName = "leashme";

	private const string VisualName = "LoxPackVisual";

	private const string RpcAdd = "LeashMe_AddPack";

	private const string RpcRemove = "LeashMe_RemovePack";

	private const string MountBoneName = "Mount";

	private const string ChestPrefabName = "piece_chest";

	private const float SinkDepth = 0.1f;

	private const string LeftTop = "Cargo_Left_Top";

	private const string RightTop = "Cargo_Right_Top";

	private const string LeftBottom = "Cargo_Left_Bottom";

	private const string RightBottom = "Cargo_Right_Bottom";

	private const string Bedroll = "Cargo_Bedroll";

	private static readonly int OwnerKey = StringExtensionMethods.GetStableHashCode("LeashMe_packOwner");

	private static GameObject s_visualPrefab;

	private static bool s_visualMissing;

	private Tameable m_tameable;

	private Container m_container;

	private GameObject m_holder;

	private GameObject m_bottomLeft;

	private GameObject m_bottomRight;

	private GameObject m_bedroll;

	private bool m_shown;

	public Tameable Tameable => m_tameable;

	public static long LocalPlayerId
	{
		get
		{
			if (!Object.op_Implicit((Object)(object)Game.instance))
			{
				return 0L;
			}
			return Game.instance.GetPlayerProfile().GetPlayerID();
		}
	}

	public bool IsLocalOwner => GetOwner(m_tameable.m_nview) == LocalPlayerId;

	public bool IsCargoEmpty
	{
		get
		{
			if (Object.op_Implicit((Object)(object)m_container))
			{
				return m_container.GetInventory().NrOfItems() == 0;
			}
			return true;
		}
	}

	public static void Attach(Tameable tameable)
	{
		if (tameable.m_nview.IsValid() && Utils.GetPrefabName(((Component)tameable).gameObject) == "Lox" && !Object.op_Implicit((Object)(object)((Component)tameable).GetComponent<PackSaddle>()))
		{
			((Component)tameable).gameObject.AddComponent<PackSaddle>().Init(tameable);
		}
	}

	public static long GetOwner(ZNetView nview)
	{
		if (!Object.op_Implicit((Object)(object)nview) || !nview.IsValid())
		{
			return 0L;
		}
		return nview.GetZDO().GetLong(OwnerKey, 0L);
	}

	public string GetCargoHoverText()
	{
		if (!Object.op_Implicit((Object)(object)m_container))
		{
			return Localization.instance.Localize("$leashme_packsaddle");
		}
		return m_container.GetHoverText();
	}

	public bool OpenCargo(Humanoid user)
	{
		if (Object.op_Implicit((Object)(object)m_container))
		{
			return m_container.Interact(user, false, false);
		}
		return false;
	}

	public static bool TryCheckAccess(Container container, long playerId, ref bool result)
	{
		PackSaddle packSaddle = (Object.op_Implicit((Object)(object)container.m_nview) ? ((Component)container.m_nview).GetComponent<PackSaddle>() : null);
		if (!Object.op_Implicit((Object)(object)packSaddle) || (Object)(object)packSaddle.m_container != (Object)(object)container)
		{
			return false;
		}
		result = playerId != 0L && GetOwner(container.m_nview) == playerId;
		return true;
	}

	public static bool TryUseItem(Tameable tameable, Humanoid user, ItemData item, ref bool result)
	{
		PackSaddle component = ((Component)tameable).GetComponent<PackSaddle>();
		if (PackSaddleItem.IsPackSaddle(item))
		{
			if (!Object.op_Implicit((Object)(object)component) || !tameable.IsTamed())
			{
				return false;
			}
			result = true;
			if (tameable.HaveSaddle() || GetOwner(tameable.m_nview) != 0L)
			{
				((Character)user).Message((MessageType)2, tameable.GetHoverName() + " $hud_saddle_already", 0, (Sprite)null, false);
				return true;
			}
			tameable.m_nview.InvokeRPC("LeashMe_AddPack", new object[1] { LocalPlayerId });
			user.GetInventory().RemoveOneItem(item);
			((Character)user).Message((MessageType)2, tameable.GetHoverName() + " $leashme_packsaddle_ready", 0, (Sprite)null, false);
			return true;
		}
		if (Object.op_Implicit((Object)(object)component) && IsVanillaSaddle(tameable, item) && GetOwner(tameable.m_nview) != 0L)
		{
			result = true;
			((Character)user).Message((MessageType)2, tameable.GetHoverName() + " $hud_saddle_already", 0, (Sprite)null, false);
			return true;
		}
		return false;
	}

	public static bool IsVanillaSaddle(Tameable tameable, ItemData item)
	{
		if (item != null && Object.op_Implicit((Object)(object)tameable.m_saddleItem))
		{
			return item.m_shared.m_name == tameable.m_saddleItem.m_itemData.m_shared.m_name;
		}
		return false;
	}

	public void RequestRemove(Humanoid user)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		m_tameable.m_nview.InvokeRPC("LeashMe_RemovePack", new object[2]
		{
			LocalPlayerId,
			((Component)user).transform.position
		});
	}

	private void Init(Tameable tameable)
	{
		m_tameable = tameable;
		m_tameable.m_nview.Register<long>("LeashMe_AddPack", (Action<long, long>)RPC_Add);
		m_tameable.m_nview.Register<long, Vector3>("LeashMe_RemovePack", (Action<long, long, Vector3>)RPC_Remove);
		Character component = ((Component)this).GetComponent<Character>();
		if (Object.op_Implicit((Object)(object)component))
		{
			component.m_onDeath = (Action)Delegate.Combine(component.m_onDeath, new Action(OnDeath));
		}
		BuildVisual();
		UpdateShown();
	}

	private void RPC_Add(long sender, long playerId)
	{
		if (m_tameable.m_nview.IsOwner() && !m_tameable.HaveSaddle() && GetOwner(m_tameable.m_nview) == 0L)
		{
			m_tameable.m_nview.GetZDO().Set(OwnerKey, playerId);
		}
	}

	private void RPC_Remove(long sender, long playerId, Vector3 userPoint)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		if (m_tameable.m_nview.IsOwner() && playerId != 0L && GetOwner(m_tameable.m_nview) == playerId && Object.op_Implicit((Object)(object)PackSaddleItem.Prefab))
		{
			if (Object.op_Implicit((Object)(object)m_container))
			{
				m_container.Load();
			}
			if (IsCargoEmpty)
			{
				m_tameable.m_nview.GetZDO().Set(OwnerKey, 0L);
				SpawnItem(userPoint - ((Component)this).transform.position);
			}
		}
	}

	private void OnDeath()
	{
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		if (!m_tameable.m_nview.IsValid() || !m_tameable.m_nview.IsOwner() || GetOwner(m_tameable.m_nview) == 0L)
		{
			return;
		}
		if (Object.op_Implicit((Object)(object)m_container))
		{
			((Component)m_container).transform.position = ((Component)this).transform.TransformPoint(m_tameable.m_dropSaddleOffset);
			m_container.Load();
			if (Object.op_Implicit((Object)(object)PackSaddleCrate.Prefab))
			{
				m_container.DropAllItems(PackSaddleCrate.Prefab);
			}
			else
			{
				m_container.DropAllItems();
			}
		}
		if (Object.op_Implicit((Object)(object)PackSaddleItem.Prefab))
		{
			SpawnItem(Vector3.zero);
		}
	}

	private void SpawnItem(Vector3 flyDirection)
	{
		//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)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown