Decompiled source of TameBond v0.1.1

TameBond.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TameBond
{
	public sealed class SpeciesList
	{
		public readonly IReadOnlyList<string> Names;

		private SpeciesList(List<string> names)
		{
			Names = names;
		}

		public static SpeciesList Parse(string csv)
		{
			List<string> list = new List<string>();
			string[] array = (csv ?? "").Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0 && !list.Contains(text))
				{
					list.Add(text);
				}
			}
			return new SpeciesList(list);
		}

		public string Of(string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return null;
			}
			foreach (string name in Names)
			{
				if (prefabName == name)
				{
					return name;
				}
			}
			return null;
		}
	}
	public sealed class YoungMap
	{
		private readonly Dictionary<string, string> map = new Dictionary<string, string>();

		public int Count => map.Count;

		public static YoungMap Parse(string csv, out string error)
		{
			error = null;
			YoungMap youngMap = new YoungMap();
			string[] array = (csv ?? "").Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length != 0)
				{
					string[] array2 = text.Split(':');
					if (array2.Length != 2 || array2[0].Trim().Length == 0 || array2[1].Trim().Length == 0)
					{
						error = "bad young entry '" + text + "', expected YoungPrefab:Species";
						return new YoungMap();
					}
					youngMap.map[array2[0].Trim()] = array2[1].Trim();
				}
			}
			return youngMap;
		}

		public string SpeciesOf(string prefabName)
		{
			if (prefabName == null || !map.TryGetValue(prefabName, out var value))
			{
				return null;
			}
			return value;
		}
	}
	public static class BondStore
	{
		public const string KeyPrefix = "syxe.TameBond.";

		public static string Key(string world)
		{
			return "syxe.TameBond." + world;
		}

		public static List<string> Read(IDictionary<string, string> data, string world)
		{
			List<string> list = new List<string>();
			if (data != null && data.TryGetValue(Key(world), out var value))
			{
				string[] array = value.Split(',');
				foreach (string text in array)
				{
					if (text.Length > 0 && !list.Contains(text))
					{
						list.Add(text);
					}
				}
			}
			return list;
		}

		public static bool Has(IDictionary<string, string> data, string world, string species)
		{
			return Read(data, world).Contains(species);
		}

		public static bool Add(IDictionary<string, string> data, string world, string species)
		{
			List<string> list = Read(data, world);
			if (list.Contains(species))
			{
				return false;
			}
			list.Add(species);
			data[Key(world)] = string.Join(",", list);
			return true;
		}
	}
	public struct Requirement
	{
		public string Item;

		public int Amount;
	}
	public static class Requirements
	{
		public static List<Requirement> Parse(string csv, out string error)
		{
			error = null;
			List<Requirement> list = new List<Requirement>();
			string[] array = (csv ?? "").Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length != 0)
				{
					string[] array2 = text.Split(':');
					if (array2.Length != 2 || array2[0].Trim().Length == 0 || !int.TryParse(array2[1].Trim(), out var result) || result < 1)
					{
						error = "bad requirement '" + text + "', expected Item:Amount";
						return new List<Requirement>();
					}
					list.Add(new Requirement
					{
						Item = array2[0].Trim(),
						Amount = result
					});
				}
			}
			return list;
		}
	}
	public sealed class StoneSpec
	{
		public string Model;

		public string Tint;

		public List<Requirement> Cost;

		public static StoneSpec Parse(string line, out string error)
		{
			error = null;
			string[] array = (line ?? "").Split('|');
			StoneSpec stoneSpec = new StoneSpec
			{
				Model = array[0].Trim(),
				Tint = ((array.Length > 1) ? array[1].Trim() : ""),
				Cost = new List<Requirement>()
			};
			if (stoneSpec.Model.Length == 0)
			{
				return stoneSpec;
			}
			if (array.Length > 3)
			{
				error = "expected model | tint | cost";
				return stoneSpec;
			}
			if (stoneSpec.Tint.Length > 0 && !TryParseTint(stoneSpec.Tint, out var _, out var _, out var _))
			{
				error = "bad tint '" + stoneSpec.Tint + "', expected #rrggbb";
				return stoneSpec;
			}
			stoneSpec.Cost = Requirements.Parse((array.Length > 2) ? array[2] : "", out error);
			return stoneSpec;
		}

		public static bool TryParseTint(string hex, out float r, out float g, out float b)
		{
			r = (g = (b = 0f));
			if (hex == null || hex.Length != 7 || hex[0] != '#')
			{
				return false;
			}
			if (!int.TryParse(hex.Substring(1), NumberStyles.HexNumber, null, out var result))
			{
				return false;
			}
			r = (float)((result >> 16) & 0xFF) / 255f;
			g = (float)((result >> 8) & 0xFF) / 255f;
			b = (float)(result & 0xFF) / 255f;
			return true;
		}
	}
	public class BondStone : MonoBehaviour, Interactable, Hoverable
	{
		public string m_species = "";

		public string m_label = "";

		public string GetHoverText()
		{
			return Localization.instance.Localize(m_label + "\n[<color=yellow><b>$KEY_Use</b></color>] $tamebond_use" + (Plugin.StonesSacrifice.Value ? "\n<color=orange>$tamebond_takes_life</color>" : "") + Unlock.BondedLine(Player.m_localPlayer));
		}

		public string GetHoverName()
		{
			return Localization.instance.Localize(m_label);
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (!hold)
			{
				Player val = (Player)(object)((user is Player) ? user : null);
				if (val != null)
				{
					if (!Plugin.StonesEnabled.Value)
					{
						((Character)val).Message((MessageType)2, Localization.instance.Localize("$tamebond_stone_off"), 0, (Sprite)null, false);
					}
					else
					{
						Unlock.Perform(val, ((Component)this).transform.position, Plugin.StonesSacrifice.Value, m_species);
					}
					return true;
				}
			}
			return false;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}
	}
	internal static class StonePiece
	{
		private static readonly Dictionary<string, GameObject> prefabs = new Dictionary<string, GameObject>();

		private static bool attempted;

		internal static void Register()
		{
			if (attempted)
			{
				return;
			}
			attempted = true;
			foreach (KeyValuePair<string, ConfigEntry<string>> stoneLine in Plugin.StoneLines)
			{
				try
				{
					Build(stoneLine.Key, stoneLine.Value.Value);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)(stoneLine.Key + " stone not registered: " + ex));
				}
			}
		}

		private static void Build(string species, string line)
		{
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: 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_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Expected O, but got Unknown
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Expected O, but got Unknown
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			string error;
			StoneSpec stoneSpec = StoneSpec.Parse(line, out error);
			if (error != null)
			{
				Plugin.Log.LogError((object)("Stones." + species + " ignored: " + error));
			}
			else
			{
				if (stoneSpec.Model.Length == 0)
				{
					return;
				}
				GameObject prefab = PrefabManager.Instance.GetPrefab(stoneSpec.Model);
				if ((Object)(object)prefab == (Object)null)
				{
					Plugin.Log.LogError((object)("Stones." + species + ": no vanilla prefab " + stoneSpec.Model + ", stone not registered"));
					return;
				}
				string text = "TameBond_" + species;
				GameObject val = PrefabManager.Instance.CreateClonedPrefab(text, prefab);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogError((object)("Stones." + species + ": clone of " + stoneSpec.Model + " failed"));
					return;
				}
				Strip(val);
				(val.GetComponent<ZNetView>() ?? val.AddComponent<ZNetView>()).m_persistent = true;
				Piece val2 = val.GetComponent<Piece>() ?? val.AddComponent<Piece>();
				GameObject prefab2 = PrefabManager.Instance.GetPrefab(species);
				Character val3 = (((Object)(object)prefab2 != (Object)null) ? prefab2.GetComponent<Character>() : null);
				string text2 = (val2.m_name = (((Object)(object)val3 != (Object)null && !string.IsNullOrEmpty(val3.m_name)) ? val3.m_name : species) + " $tamebond_stone");
				val2.m_description = "$tamebond_stone_desc";
				val2.m_canBeRemoved = true;
				val2.m_enabled = Plugin.StonesEnabled.Value;
				if ((Object)(object)val.GetComponent<WearNTear>() == (Object)null)
				{
					WearNTear obj = val.AddComponent<WearNTear>();
					obj.m_health = 500f;
					obj.m_noRoofWear = true;
					obj.m_noSupportWear = true;
				}
				BondStone bondStone = val.AddComponent<BondStone>();
				bondStone.m_species = species;
				bondStone.m_label = text2;
				if (stoneSpec.Tint.Length > 0 && StoneSpec.TryParseTint(stoneSpec.Tint, out var r, out var g, out var b))
				{
					Tint(val, new Color(r, g, b));
				}
				PieceConfig val4 = new PieceConfig
				{
					Name = text2,
					Description = val2.m_description,
					PieceTable = PieceTables.Hammer,
					Category = PieceCategories.Misc,
					Icon = val2.m_icon,
					Enabled = Plugin.StonesEnabled.Value,
					Requirements = Cost(stoneSpec)
				};
				if (!string.IsNullOrEmpty(Plugin.StoneStation.Value))
				{
					val4.CraftingStation = Plugin.StoneStation.Value;
				}
				if (!PieceManager.Instance.AddPiece(new CustomPiece(val, false, val4)))
				{
					Plugin.Log.LogError((object)("Jotunn refused the " + species + " stone"));
					return;
				}
				prefabs[species] = val;
				Plugin.Log.LogInfo((object)(species + " stone registered from " + stoneSpec.Model + ", cost " + line));
			}
		}

		private static void Strip(GameObject prefab)
		{
			MonoBehaviour[] componentsInChildren = prefab.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !(val is Piece) && !(val is WearNTear) && !(val is ZNetView) && !(val is ZSyncTransform) && (val is Interactable || val is Hoverable || val is Fireplace || val is Beehive || val is Chair || val is Container || val is Sign || val is Bed || val is Switch))
				{
					Object.DestroyImmediate((Object)(object)val);
				}
			}
		}

		private static void Tint(GameObject prefab, Color c)
		{
			//IL_0048: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				Material[] materials = val.materials;
				Material[] array = materials;
				foreach (Material val2 in array)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						if (val2.HasProperty("_Color"))
						{
							val2.SetColor("_Color", c);
						}
						if (val2.HasProperty("_EmissionColor"))
						{
							val2.EnableKeyword("_EMISSION");
							val2.SetColor("_EmissionColor", c * 0.3f);
						}
					}
				}
				val.materials = materials;
			}
		}

		private static RequirementConfig[] Cost(StoneSpec spec)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			List<RequirementConfig> list = new List<RequirementConfig>();
			foreach (Requirement item in spec.Cost)
			{
				list.Add(new RequirementConfig(item.Item, item.Amount, 0, Plugin.RefundOnRemove.Value));
			}
			return list.ToArray();
		}

		internal static string PlacementRefusal(Player player)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.StonesEnabled.Value)
			{
				return "$tamebond_stone_off";
			}
			if (Plugin.BedDistance.Value <= 0f)
			{
				return null;
			}
			PlayerProfile val = (((Object)(object)Game.instance != (Object)null) ? Game.instance.GetPlayerProfile() : null);
			if (val == null || !val.HaveCustomSpawnPoint())
			{
				return "$tamebond_no_bed";
			}
			if (!(Vector3.Distance(val.GetCustomSpawnPoint(), ((Component)player).transform.position) <= Plugin.BedDistance.Value))
			{
				return "$tamebond_far_from_bed";
			}
			return null;
		}

		internal static void ApplyEnabled()
		{
			foreach (KeyValuePair<string, GameObject> prefab in prefabs)
			{
				Piece component = prefab.Value.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null)
				{
					component.m_enabled = Plugin.StonesEnabled.Value;
				}
			}
			Plugin.Log.LogInfo((object)("bond stones " + (Plugin.StonesEnabled.Value ? "enabled" : "disabled")));
		}

		internal static void ApplyCost(string species)
		{
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			if (!prefabs.TryGetValue(species, out var value) || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			Piece component = value.GetComponent<Piece>();
			string error;
			StoneSpec stoneSpec = StoneSpec.Parse(Plugin.StoneLines[species].Value, out error);
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			if (error != null)
			{
				Plugin.Log.LogError((object)("Stones." + species + " ignored: " + error));
				return;
			}
			List<Requirement> list = new List<Requirement>();
			foreach (Requirement item in stoneSpec.Cost)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item.Item);
				ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogError((object)("Stones." + species + " ignored: no item " + item.Item));
					return;
				}
				list.Add(new Requirement
				{
					m_resItem = val,
					m_amount = item.Amount,
					m_recover = Plugin.RefundOnRemove.Value
				});
			}
			component.m_resources = list.ToArray();
			Plugin.Log.LogInfo((object)(species + " stone cost now " + Plugin.StoneLines[species].Value));
		}
	}
	[HarmonyPatch(typeof(Vegvisir), "Interact")]
	internal static class VegvisirInteract
	{
		private static bool Prefix(Vegvisir __instance, Humanoid character, bool hold, bool alt)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (!(!alt || hold) && Plugin.VegvisirEnabled.Value)
			{
				Player val = (Player)(object)((character is Player) ? character : null);
				if (val != null)
				{
					if (!SpawnStone.Is(__instance))
					{
						((Character)val).Message((MessageType)2, Localization.instance.Localize("$tamebond_not_spawn"), 0, (Sprite)null, false);
					}
					else
					{
						Unlock.Perform(val, ((Component)__instance).transform.position, Plugin.VegvisirSacrifice.Value);
					}
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Vegvisir), "GetHoverText")]
	internal static class VegvisirHover
	{
		private static void Postfix(Vegvisir __instance, ref string __result)
		{
			if (Plugin.VegvisirEnabled.Value && SpawnStone.Is(__instance))
			{
				__result += Localization.instance.Localize("\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] $tamebond_use" + (Plugin.VegvisirSacrifice.Value ? "\n<color=orange>$tamebond_takes_life</color>" : "") + Unlock.BondedLine(Player.m_localPlayer));
			}
		}
	}
	internal static class SpawnStone
	{
		private static readonly Dictionary<Vector3, string> icons = new Dictionary<Vector3, string>();

		internal static bool Is(Vegvisir v)
		{
			//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)
			if (!Plugin.VegvisirSpawnOnly.Value)
			{
				return true;
			}
			if ((Object)(object)ZoneSystem.instance == (Object)null)
			{
				return false;
			}
			icons.Clear();
			ZoneSystem.instance.GetLocationIcons(icons);
			foreach (KeyValuePair<Vector3, string> icon in icons)
			{
				if (icon.Value == "StartTemple" && Vector3.Distance(icon.Key, ((Component)v).transform.position) <= Plugin.SpawnDistance.Value)
				{
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "TryPlacePiece")]
	internal static class PlaceBondStone
	{
		private static bool Prefix(Player __instance, Piece piece, ref bool __result)
		{
			if ((Object)(object)piece == (Object)null || (Object)(object)((Component)piece).GetComponent<BondStone>() == (Object)null)
			{
				return true;
			}
			string text = StonePiece.PlacementRefusal(__instance);
			if (text == null)
			{
				return true;
			}
			((Character)__instance).Message((MessageType)2, Localization.instance.Localize(text), 0, (Sprite)null, false);
			__result = false;
			return false;
		}
	}
	[HarmonyPatch]
	internal static class TeleportCreaturesGate
	{
		private const string TypeName = "TeleportCreatures.EffectiveCreaturePolicy";

		private static MethodBase target;

		private static bool Prepare(MethodBase original)
		{
			if (original != null)
			{
				return true;
			}
			bool flag = Chainloader.PluginInfos.ContainsKey("odinplus.TeleportCreatures");
			Type type = AccessTools.TypeByName("TeleportCreatures.EffectiveCreaturePolicy");
			if (type == null)
			{
				if (flag)
				{
					Plugin.Log.LogError((object)"TeleportCreatures is loaded but TeleportCreatures.EffectiveCreaturePolicy is missing: the bond gate is OFF, tames travel ungated");
				}
				else
				{
					Plugin.Log.LogWarning((object)"TeleportCreatures not loaded: bond gate not installed");
				}
				return false;
			}
			target = AccessTools.FirstMethod(type, (Func<MethodInfo, bool>)delegate(MethodInfo m)
			{
				if (m.Name != "IsAllowed" || m.IsStatic || m.ReturnType != typeof(bool))
				{
					return false;
				}
				ParameterInfo[] parameters = m.GetParameters();
				return parameters.Length == 5 && parameters[0].ParameterType == typeof(string) && parameters[0].Name == "prefabName" && parameters[1].ParameterType == typeof(bool) && parameters[1].Name == "isTamed" && parameters[2].ParameterType == typeof(bool) && parameters[3].ParameterType == typeof(bool);
			});
			if (target == null)
			{
				Plugin.Log.LogError((object)"TeleportCreatures.EffectiveCreaturePolicy.IsAllowed(string prefabName, bool isTamed, bool, bool, PortalContext) not found: the bond gate is OFF, tames travel ungated. Pin TeleportCreatures or update TameBond.");
				return false;
			}
			Plugin.Log.LogInfo((object)("bond gate on TeleportCreatures.EffectiveCreaturePolicy." + target.Name));
			return true;
		}

		private static MethodBase TargetMethod()
		{
			return target;
		}

		private static void Postfix(ref bool __result, string prefabName, bool isTamed)
		{
			if (__result && isTamed)
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && !Unlock.Allows(localPlayer, prefabName))
				{
					__result = false;
				}
			}
		}
	}
	[BepInPlugin("syxe.TameBond", "TameBond", "0.1.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public enum UnlistedRule
		{
			Free,
			Blocked
		}

		public const string Guid = "syxe.TameBond";

		public const string Name = "TameBond";

		public const string Version = "0.1.1";

		public const string TeleportCreaturesGuid = "odinplus.TeleportCreatures";

		internal static ManualLogSource Log;

		internal static SpeciesList Species = SpeciesList.Parse("");

		internal static YoungMap Young = YoungMap.Parse("", out var _);

		internal static ConfigEntry<string> SpeciesCfg;

		internal static ConfigEntry<UnlistedRule> Unlisted;

		internal static ConfigEntry<string> YoungCfg;

		internal static ConfigEntry<bool> YoungTravel;

		internal static ConfigEntry<float> UnlockRadius;

		internal static ConfigEntry<bool> VegvisirEnabled;

		internal static ConfigEntry<bool> VegvisirSpawnOnly;

		internal static ConfigEntry<float> SpawnDistance;

		internal static ConfigEntry<bool> VegvisirSacrifice;

		internal static ConfigEntry<bool> StonesSacrifice;

		internal static ConfigEntry<bool> StonesEnabled;

		internal static ConfigEntry<float> BedDistance;

		internal static ConfigEntry<bool> RefundOnRemove;

		internal static ConfigEntry<string> StoneStation;

		internal static readonly Dictionary<string, ConfigEntry<string>> StoneLines = new Dictionary<string, ConfigEntry<string>>();

		private static readonly Dictionary<string, string> DefaultStones = new Dictionary<string, string>
		{
			["Boar"] = "piece_beehive | #D9A441 | DeerHide:20,Bronze:5,TrophyBoar:3",
			["Wolf"] = "darkwood_wolf | #8FC7FF | WolfPelt:20,Silver:5,TrophyWolf:3",
			["Lox"] = "darkwood_raven | #E0B050 | LoxPelt:20,BlackMetal:5,TrophyLox:3",
			["Asksvin"] = "piece_wisplure | #FF7A30 | ScaleHide:20,FlametalNew:5,TrophyAsksvin:3",
			["Moose"] = "piece_moose_throne | #7FE0C8 | MooseHide:20,Gold:5,TrophyMoose:3"
		};

		private Harmony harmony;

		private void Awake()
		{
			//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_0018: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Expected O, but got Unknown
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Expected O, but got Unknown
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Expected O, but got Unknown
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Expected O, but got Unknown
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Expected O, but got Unknown
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Expected O, but got Unknown
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_024f: Expected O, but got Unknown
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Expected O, but got Unknown
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Expected O, but got Unknown
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Expected O, but got Unknown
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0369: Expected O, but got Unknown
			//IL_0547: Unknown result type (might be due to invalid IL or missing references)
			//IL_0573: Unknown result type (might be due to invalid IL or missing references)
			//IL_057d: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
			SpeciesCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Species", "List", "Boar,Wolf,Lox,Asksvin,Moose", new ConfigDescription("Prefab names of the species that need a bond before they follow through a portal. A species added here gets its Stones line at the next game start.", (AcceptableValueBase)null, new object[1] { val }));
			YoungCfg = ((BaseUnityPlugin)this).Config.Bind<string>("Species", "Young", "Boar_piggy:Boar,Wolf_cub:Wolf,Lox_Calf:Lox,Asksvin_hatchling:Asksvin,Moose_calf:Moose", new ConfigDescription("Juvenile prefab to species, as YoungPrefab:Species pairs. Young never count for a bond; whether they travel is YoungTravel.", (AcceptableValueBase)null, new object[1] { val }));
			YoungTravel = ((BaseUnityPlugin)this).Config.Bind<bool>("Species", "YoungTravel", false, new ConfigDescription("Let a listed young animal follow a player who holds its species' bond. Off, young never go through a portal.", (AcceptableValueBase)null, new object[1] { val }));
			Unlisted = ((BaseUnityPlugin)this).Config.Bind<UnlistedRule>("Species", "UnlistedSpecies", UnlistedRule.Blocked, new ConfigDescription("Species not in the list: Free leaves them to TeleportCreatures' own policy, Blocked never lets them through.", (AcceptableValueBase)null, new object[1] { val }));
			UnlockRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Unlock", "Radius", 10f, new ConfigDescription("Metres around the stone within which a tame counts for the bond.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), new object[1] { val }));
			VegvisirEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Vegvisir", "Enabled", true, new ConfigDescription("Shift + Use on a Vegvisir bonds every listed species in range. Plain Use keeps its vanilla job.", (AcceptableValueBase)null, new object[1] { val }));
			VegvisirSpawnOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Vegvisir", "SpawnOnly", true, new ConfigDescription("Only the Vegvisir at the start temple bonds; other boss stones refuse.", (AcceptableValueBase)null, new object[1] { val }));
			SpawnDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Vegvisir", "SpawnDistance", 100f, new ConfigDescription("Metres from the StartTemple location within which a Vegvisir counts as the spawn stone.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 500f), new object[1] { val }));
			VegvisirSacrifice = ((BaseUnityPlugin)this).Config.Bind<bool>("Vegvisir", "Sacrifice", true, new ConfigDescription("Bonding at the Vegvisir kills the animal bonded (one per kind), so each player brings their own.", (AcceptableValueBase)null, new object[1] { val }));
			StonesSacrifice = ((BaseUnityPlugin)this).Config.Bind<bool>("Stones", "Sacrifice", true, new ConfigDescription("Bonding at a bond stone kills the animal bonded.", (AcceptableValueBase)null, new object[1] { val }));
			StonesEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Stones", "Enabled", false, new ConfigDescription("Offer the per-species bond stones in the hammer and let placed stones bond. Off (the default), only the spawn Vegvisir bonds.", (AcceptableValueBase)null, new object[1] { val }));
			BedDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Stones", "BedDistance", 50f, new ConfigDescription("A stone can only be placed this close to the placer's own bed (spawn point); 0 lifts the rule.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 500f), new object[1] { val }));
			RefundOnRemove = ((BaseUnityPlugin)this).Config.Bind<bool>("Stones", "RefundOnRemove", false, new ConfigDescription("Give the materials back when a stone is picked up with the hammer. Read at game start.", (AcceptableValueBase)null, new object[1] { val }));
			StoneStation = ((BaseUnityPlugin)this).Config.Bind<string>("Stones", "CraftingStation", "piece_workbench", new ConfigDescription("Crafting station a stone needs nearby; empty for none. Read at game start.", (AcceptableValueBase)null, new object[1] { val }));
			foreach (string name in SpeciesList.Parse(SpeciesCfg.Value).Names)
			{
				DefaultStones.TryGetValue(name, out var value);
				StoneLines[name] = ((BaseUnityPlugin)this).Config.Bind<string>("Stones", name, value ?? "", new ConfigDescription("This species' stone as 'model | #rrggbb tint | Item:Amount,...': a vanilla buildable to clone, a tint for its materials, the build cost. Empty: no stone. Model and tint are read at game start, the cost applies live.", (AcceptableValueBase)null, new object[1] { val }));
				string s = name;
				StoneLines[name].SettingChanged += delegate
				{
					StonePiece.ApplyCost(s);
				};
			}
			Species = SpeciesList.Parse(SpeciesCfg.Value);
			SpeciesCfg.SettingChanged += delegate
			{
				Species = SpeciesList.Parse(SpeciesCfg.Value);
			};
			LoadYoung();
			YoungCfg.SettingChanged += delegate
			{
				LoadYoung();
			};
			StonesEnabled.SettingChanged += delegate
			{
				StonePiece.ApplyEnabled();
			};
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				["tamebond_stone"] = "bond stone",
				["tamebond_stone_desc"] = "Bring one of them here and use the stone: that kind may then follow you through portals.",
				["tamebond_use"] = "Bond tames in range",
				["tamebond_bonded"] = "Bonded with",
				["tamebond_given"] = "the animal is given to the stone",
				["tamebond_takes_life"] = "Bonding takes the animal's life",
				["tamebond_already"] = "Already bonded with",
				["tamebond_none"] = "No tame of a bondable kind is near the stone",
				["tamebond_not_spawn"] = "Only the stone at the start temple binds tames",
				["tamebond_no_world"] = "Not in a world",
				["tamebond_bonded_here"] = "Bonded here",
				["tamebond_stone_off"] = "Bond stones are not in use on this server",
				["tamebond_no_bed"] = "A bond stone stands near your bed; claim one first",
				["tamebond_far_from_bed"] = "Too far from your bed for a bond stone"
			});
			new ConfigFileWatcher(((BaseUnityPlugin)this).Config, 1000L);
			PrefabManager.OnVanillaPrefabsAvailable += StonePiece.Register;
			harmony = new Harmony("syxe.TameBond");
			harmony.PatchAll(typeof(Plugin).Assembly);
			if (Chainloader.PluginInfos.TryGetValue("odinplus.TeleportCreatures", out var value2))
			{
				Log.LogInfo((object)("TameBond 0.1.1 with TeleportCreatures " + value2.Metadata.Version));
			}
			else
			{
				Log.LogWarning((object)"TameBond 0.1.1: TeleportCreatures is not loaded, so nothing transports tames; bonds are still recorded");
			}
		}

		private static void LoadYoung()
		{
			Young = YoungMap.Parse(YoungCfg.Value, out var error);
			if (error != null)
			{
				Log.LogError((object)("Species.Young ignored: " + error));
			}
		}

		internal static string WorldKey()
		{
			string text = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : null);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return null;
		}
	}
	internal static class Unlock
	{
		internal static Dictionary<string, Character> SpeciesNear(Vector3 point, float radius, string only = null)
		{
			//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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, Character> dictionary = new Dictionary<string, Character>();
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if ((Object)(object)allCharacter == (Object)null || !allCharacter.IsTamed() || allCharacter.IsDead())
				{
					continue;
				}
				float num = Vector3.Distance(((Component)allCharacter).transform.position, point);
				if (!(num > radius))
				{
					string text = Plugin.Species.Of(Utils.GetPrefabName(((Component)allCharacter).gameObject));
					if (text != null && (only == null || !(text != only)) && (!dictionary.TryGetValue(text, out var value) || num < Vector3.Distance(((Component)value).transform.position, point)))
					{
						dictionary[text] = allCharacter;
					}
				}
			}
			return dictionary;
		}

		internal static void Perform(Player player, Vector3 point, bool sacrifice, string only = null)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			string text = Plugin.WorldKey();
			if (text == null)
			{
				Say(player, "$tamebond_no_world");
				return;
			}
			Dictionary<string, Character> dictionary = SpeciesNear(point, Plugin.UnlockRadius.Value, only);
			if (dictionary.Count == 0)
			{
				Say(player, "$tamebond_none");
				return;
			}
			List<string> list = new List<string>();
			List<string> list2 = new List<string>();
			foreach (KeyValuePair<string, Character> item in dictionary)
			{
				if (!BondStore.Add(player.m_customData, text, item.Key))
				{
					list2.Add(item.Value.m_name);
					continue;
				}
				list.Add(item.Value.m_name);
				if (sacrifice)
				{
					Kill(item.Value);
				}
			}
			if (list.Count > 0)
			{
				Say(player, "$tamebond_bonded " + string.Join(", ", list) + (sacrifice ? "; $tamebond_given" : ""));
				Plugin.Log.LogInfo((object)("bonded " + player.GetPlayerName() + " in " + text + " with " + string.Join(",", list) + (sacrifice ? ", sacrificed" : "")));
			}
			else
			{
				Say(player, "$tamebond_already " + string.Join(", ", list2));
			}
		}

		private static void Kill(Character c)
		{
			ZNetView component = ((Component)c).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid())
			{
				if (!component.IsOwner())
				{
					component.ClaimOwnership();
				}
				c.SetHealth(0f);
			}
		}

		internal static bool Allows(Player player, string prefabName)
		{
			string text = Plugin.Young.SpeciesOf(prefabName);
			if (text != null && !Plugin.YoungTravel.Value)
			{
				return false;
			}
			string text2 = text ?? Plugin.Species.Of(prefabName);
			if (text2 == null)
			{
				return Plugin.Unlisted.Value == Plugin.UnlistedRule.Free;
			}
			string text3 = Plugin.WorldKey();
			if (text3 != null)
			{
				return BondStore.Has(player.m_customData, text3, text2);
			}
			return false;
		}

		internal static string BondedLine(Player player)
		{
			string text = Plugin.WorldKey();
			if ((Object)(object)player == (Object)null || text == null)
			{
				return "";
			}
			List<string> list = BondStore.Read(player.m_customData, text);
			if (list.Count != 0)
			{
				return "\n$tamebond_bonded_here: " + string.Join(", ", list);
			}
			return "";
		}

		private static void Say(Player player, string text)
		{
			((Character)player).Message((MessageType)2, Localization.instance.Localize(text), 0, (Sprite)null, false);
		}
	}
}