Decompiled source of FehuMounts v420.0.2

FehuMounts.dll

Decompiled 19 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

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

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 FehuMounts
{
	[BepInPlugin("wmymysl.fehumounts", "FehuMounts", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "wmymysl.fehumounts";

		public const string ModName = "FehuMounts";

		public const string ModVersion = "1.0.0";

		internal static ConfigEntry<bool> EnableDeerTaming = null;

		internal static ConfigEntry<string> DeerTamingFoods = null;

		internal static ConfigEntry<int> MinStarsToRide = null;

		internal static ConfigEntry<bool> EnableWhistle = null;

		internal static ConfigEntry<bool> RegisterWhistleItem = null;

		internal static ConfigEntry<float> WhistleRange = null;

		internal static ConfigEntry<bool> OnlyOwnerCanSummon = null;

		internal static readonly int FehuOwnerHash = StableHash("FehuMounts.Owner");

		internal static readonly int FehuOwnerNameHash = StableHash("FehuMounts.OwnerName");

		internal static readonly int FehuLegendaryCallHash = StableHash("FehuMounts.LegendaryCall");

		internal const string WhistlePrefabName = "FehuWhistle";

		internal const string WhistleToken = "$item_fehu_whistle";

		internal const string CallMountRpc = "FehuMounts_CallMount";

		internal const string ConfigSyncRpc = "FehuMounts_ConfigSync";

		private static readonly Harmony Harmony = new Harmony("wmymysl.fehumounts");

		private static readonly HashSet<string> RegisteredObjectDb = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> RegisteredZNetScene = new HashSet<string>(StringComparer.Ordinal);

		private void Awake()
		{
			EnableDeerTaming = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableDeerTaming", true, "Enable taming support for vanilla Deer.");
			DeerTamingFoods = ((BaseUnityPlugin)this).Config.Bind<string>("General", "DeerTamingFoods", "Raspberry,Blueberry,Blueberries,Carrot,Turnip", "Comma-separated prefab names that Deer can eat while taming. Blueberry and Blueberries are both accepted.");
			MinStarsToRide = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MinStarsToRide", 2, "Minimum deer stars required to ride. Vanilla level is stars + 1.");
			EnableWhistle = ((BaseUnityPlugin)this).Config.Bind<bool>("Whistle", "EnableWhistle", false, "Enable Fehu Whistle item and summon behavior. Disabled by default while deer taming is validated with mixed ItemManager modlists.");
			RegisterWhistleItem = ((BaseUnityPlugin)this).Config.Bind<bool>("Whistle", "RegisterWhistleItem", false, "Register the Fehu Whistle item prefab and recipe. Keep false while testing deer taming if ItemManager mods throw prefab errors.");
			WhistleRange = ((BaseUnityPlugin)this).Config.Bind<float>("Whistle", "WhistleRange", 80f, "Range in meters for finding an owned tamed deer.");
			OnlyOwnerCanSummon = ((BaseUnityPlugin)this).Config.Bind<bool>("Whistle", "OnlyOwnerCanSummon", true, "Only the recorded deer owner may summon it.");
			ConfigSync.HookSettings();
			Harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"FehuMounts 1.0.0 loaded.");
		}

		private void OnDestroy()
		{
			Harmony.UnpatchSelf();
		}

		internal static bool IsDeer(Character? character)
		{
			if ((Object)(object)character != (Object)null)
			{
				return Utils.GetPrefabName(((Component)character).gameObject).Equals("Deer", StringComparison.OrdinalIgnoreCase);
			}
			return false;
		}

		internal static int GetStars(Character character)
		{
			return Math.Max(0, character.GetLevel() - 1);
		}

		internal static bool CanRide(Character character)
		{
			if (IsDeer(character))
			{
				return GetStars(character) >= Math.Max(0, MinStarsToRide.Value);
			}
			return false;
		}

		internal static MountTier GetTier(Character character)
		{
			int stars = GetStars(character);
			if (stars < 5)
			{
				return stars switch
				{
					4 => new MountTier(1.25f, 1.4f, 0.85f, legendaryRecall: false), 
					3 => new MountTier(1.15f, 1.25f, 1f, legendaryRecall: false), 
					_ => new MountTier(1f, 1f, 1f, legendaryRecall: false), 
				};
			}
			return new MountTier(1.35f, 1.6f, 0.7f, legendaryRecall: true);
		}

		internal static void ConfigureDeer(GameObject deer)
		{
			Character component = deer.GetComponent<Character>();
			MonsterAI component2 = deer.GetComponent<MonsterAI>();
			ZNetView nview = deer.GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)nview == (Object)null)
			{
				return;
			}
			if (nview.IsValid())
			{
				nview.Unregister("FehuMounts_CallMount");
				nview.Register<long, string, Vector3>("FehuMounts_CallMount", (Action<long, long, string, Vector3>)delegate(long sender, long playerId, string playerName, Vector3 playerPos)
				{
					//IL_0009: Unknown result type (might be due to invalid IL or missing references)
					RPC_CallMount(nview, sender, playerId, playerName, playerPos);
				});
			}
			if (EnableDeerTaming.Value)
			{
				Tameable val = deer.GetComponent<Tameable>() ?? deer.AddComponent<Tameable>();
				val.m_commandable = true;
				val.m_startsTamed = false;
				val.m_tamingTime = Math.Max(1f, val.m_tamingTime);
				val.m_fedDuration = Math.Max(30f, val.m_fedDuration);
				Tameable val2 = val;
				if (val2.m_randomStartingName == null)
				{
					val2.m_randomStartingName = new List<string>();
				}
				AddFoods(component2);
				component2.m_fleeIfNotAlerted = false;
				component2.m_fleeIfHurtWhenTargetCantBeReached = false;
				component2.m_fleeIfLowHealth = 0f;
				component2.m_consumeRange = Math.Max(component2.m_consumeRange, 2f);
				component2.m_consumeSearchRange = Math.Max(component2.m_consumeSearchRange, 10f);
			}
			Tameable component3 = deer.GetComponent<Tameable>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.m_saddleItem = null;
				component3.m_dropSaddleOnDeath = false;
			}
		}

		internal static Sadle EnsureRideController(GameObject deer, Character character, Tameable tameable)
		{
			//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)
			Sadle val = deer.GetComponent<Sadle>() ?? deer.AddComponent<Sadle>();
			val.m_hoverText = "Ride Deer";
			val.m_maxUseRange = 4f;
			val.m_attachAnimation = "attach_chair";
			val.m_detachOffset = new Vector3(0f, 0.2f, -1.2f);
			val.m_attachPoint = EnsureAttachPoint(deer.transform);
			ApplyTierStats(val, character);
			tameable.m_saddle = val;
			tameable.m_saddleItem = null;
			tameable.m_dropSaddleOnDeath = false;
			return val;
		}

		internal static void ApplyTierStats(Sadle sadle, Character character)
		{
			MountTier tier = GetTier(character);
			sadle.m_maxStamina = 100f * tier.StaminaMultiplier;
			sadle.m_runStaminaDrain = 10f * tier.StaminaDrainMultiplier;
			sadle.m_swimStaminaDrain = 20f * tier.StaminaDrainMultiplier;
			sadle.m_staminaRegen = 15f * tier.StaminaMultiplier;
			sadle.m_staminaRegenHungry = 5f;
		}

		internal static bool IsWhistle(ItemData? item)
		{
			if ((Object)(object)item?.m_dropPrefab != (Object)null)
			{
				return Utils.GetPrefabName(item.m_dropPrefab) == "FehuWhistle";
			}
			return false;
		}

		internal static void UseWhistle(Player player)
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			if (!EnableWhistle.Value)
			{
				((Character)player).Message((MessageType)2, "The whistle is silent.", 0, (Sprite)null);
				return;
			}
			Tameable val = FindNearestOwnedTamedDeer(player, WhistleRange.Value);
			if ((Object)(object)val == (Object)null)
			{
				((Character)player).Message((MessageType)2, "No loyal deer answers.", 0, (Sprite)null);
				return;
			}
			ZNetView component = ((Component)val).GetComponent<ZNetView>();
			Character component2 = ((Component)val).GetComponent<Character>();
			MonsterAI component3 = ((Component)val).GetComponent<MonsterAI>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null) && !((Object)(object)component3 == (Object)null) && component.IsValid())
			{
				component.InvokeRPC(ZNetView.Everybody, "FehuMounts_CallMount", new object[3]
				{
					player.GetPlayerID(),
					player.GetPlayerName(),
					((Component)player).transform.position
				});
				((Character)player).Message((MessageType)2, val.GetName() + " hears the whistle.", 0, (Sprite)null);
			}
		}

		internal static void StoreOwnerIfMissing(ZNetView? nview, Player? player)
		{
			if (!((Object)(object)nview == (Object)null) && !((Object)(object)player == (Object)null) && nview.IsValid())
			{
				ZDO zDO = nview.GetZDO();
				if (zDO.GetLong(FehuOwnerHash, 0L) == 0L)
				{
					StoreOwnerData(zDO, player.GetPlayerID(), player.GetPlayerName());
				}
			}
		}

		internal static void StoreOwnerData(ZDO zdo, long playerId, string playerName)
		{
			zdo.Set(FehuOwnerHash, playerId);
			zdo.Set(FehuOwnerNameHash, playerName);
		}

		private static void RPC_CallMount(ZNetView nview, long sender, long playerId, string playerName, Vector3 playerPos)
		{
			//IL_00b2: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			if (!nview.IsValid() || !nview.IsOwner())
			{
				return;
			}
			Tameable component = ((Component)nview).GetComponent<Tameable>();
			Character component2 = ((Component)nview).GetComponent<Character>();
			MonsterAI component3 = ((Component)nview).GetComponent<MonsterAI>();
			if (IsDeer(component2) && !((Object)(object)component == (Object)null) && !((Object)(object)component3 == (Object)null) && component.IsTamed())
			{
				ZDO zDO = nview.GetZDO();
				long num = zDO.GetLong(FehuOwnerHash, 0L);
				if (num == 0L)
				{
					StoreOwnerData(zDO, playerId, playerName);
				}
				else if (OnlyOwnerCanSummon.Value && num != playerId)
				{
					return;
				}
				Player player = Player.GetPlayer(playerId);
				if ((Object)(object)player != (Object)null)
				{
					component3.SetFollowTarget(((Component)player).gameObject);
				}
				if (GetTier(component2).LegendaryRecall && Vector3.Distance(playerPos, ((Component)component2).transform.position) > 25f)
				{
					Vector3 position = (((Object)(object)player != (Object)null) ? (((Component)player).transform.position - ((Component)player).transform.forward * 3f) : playerPos);
					((Component)component2).transform.position = position;
					zDO.SetPosition(position);
					zDO.Set(FehuLegendaryCallHash, ((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTime().Ticks : DateTime.UtcNow.Ticks);
				}
			}
		}

		private static Tameable? FindNearestOwnedTamedDeer(Player player, float range)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			Tameable result = null;
			float num = range;
			foreach (BaseAI allInstance in BaseAI.GetAllInstances())
			{
				Character component = ((Component)allInstance).GetComponent<Character>();
				Tameable component2 = ((Component)allInstance).GetComponent<Tameable>();
				ZNetView component3 = ((Component)allInstance).GetComponent<ZNetView>();
				if (IsDeer(component) && !((Object)(object)component2 == (Object)null) && !((Object)(object)component3 == (Object)null) && component3.IsValid() && component2.IsTamed() && (!OnlyOwnerCanSummon.Value || IsOwner(component3, player)))
				{
					float num2 = Vector3.Distance(((Component)player).transform.position, ((Component)component).transform.position);
					if (num2 <= num)
					{
						result = component2;
						num = num2;
					}
				}
			}
			return result;
		}

		private static bool IsOwner(ZNetView nview, Player player)
		{
			long num = nview.GetZDO().GetLong(FehuOwnerHash, 0L);
			if (num != 0L)
			{
				return num == player.GetPlayerID();
			}
			return true;
		}

		private static Transform EnsureAttachPoint(Transform root)
		{
			//IL_001c: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			Transform val = root.Find("FehuMountAttachPoint");
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			GameObject val2 = new GameObject("FehuMountAttachPoint");
			val2.transform.SetParent(root, false);
			val2.transform.localPosition = new Vector3(0f, 1f, -0.15f);
			val2.transform.localRotation = Quaternion.identity;
			return val2.transform;
		}

		private static void AddFoods(MonsterAI ai)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			if (ai.m_consumeItems == null)
			{
				ai.m_consumeItems = new List<ItemDrop>();
			}
			foreach (string item in from s in DeerTamingFoods.Value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
				select NormalizeFoodPrefab(s.Trim()))
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item);
				ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if ((Object)(object)val != (Object)null && !ai.m_consumeItems.Contains(val))
				{
					ai.m_consumeItems.Add(val);
				}
			}
		}

		private static string NormalizeFoodPrefab(string prefabName)
		{
			if (!prefabName.Equals("Blueberry", StringComparison.OrdinalIgnoreCase))
			{
				return prefabName;
			}
			return "Blueberries";
		}

		internal static void RegisterWhistle(ObjectDB objectDb)
		{
			//IL_00cd: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
			if (EnableWhistle.Value && RegisterWhistleItem.Value && !RegisteredObjectDb.Contains("FehuWhistle"))
			{
				GameObject itemPrefab = objectDb.GetItemPrefab("BoneFragments");
				if (!((Object)(object)itemPrefab == (Object)null))
				{
					GameObject val = Object.Instantiate<GameObject>(itemPrefab);
					((Object)val).name = "FehuWhistle";
					Object.DontDestroyOnLoad((Object)(object)val);
					ItemDrop component = val.GetComponent<ItemDrop>();
					component.m_itemData.m_shared.m_name = "Fehu Whistle";
					component.m_itemData.m_shared.m_description = "A carved whistle used to call loyal mounts.";
					component.m_itemData.m_shared.m_maxStackSize = 1;
					component.m_itemData.m_shared.m_weight = 0.2f;
					component.m_itemData.m_shared.m_value = 5;
					component.m_itemData.m_shared.m_itemType = (ItemType)18;
					component.m_itemData.m_dropPrefab = val;
					val.transform.localScale = Vector3.one * 0.3f;
					objectDb.m_items.Add(val);
					objectDb.m_recipes.Add(CreateWhistleRecipe(objectDb, component));
					RegisteredObjectDb.Add("FehuWhistle");
				}
			}
		}

		internal static void RegisterWhistleScenePrefab(ZNetScene scene)
		{
			if (EnableWhistle.Value && RegisterWhistleItem.Value && !RegisteredZNetScene.Contains("FehuWhistle") && !((Object)(object)ObjectDB.instance == (Object)null))
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("FehuWhistle");
				if ((Object)(object)itemPrefab != (Object)null && !scene.m_prefabs.Contains(itemPrefab))
				{
					scene.m_prefabs.Add(itemPrefab);
					RegisteredZNetScene.Add("FehuWhistle");
				}
			}
		}

		internal static void ConfigureDeerPrefab(ZNetScene scene)
		{
			GameObject val = ((IEnumerable<GameObject>)scene.m_prefabs).FirstOrDefault((Func<GameObject, bool>)((GameObject prefab) => (Object)(object)prefab != (Object)null && ((Object)prefab).name == "Deer")) ?? scene.GetPrefab("Deer");
			if ((Object)(object)val != (Object)null)
			{
				ConfigureDeer(val);
			}
		}

		internal static void UpdateRideController(Tameable tameable)
		{
			Character component = ((Component)tameable).GetComponent<Character>();
			if (IsDeer(component))
			{
				((Component)tameable).GetComponent<Sadle>();
				if (!tameable.IsTamed() || !CanRide(component))
				{
					tameable.m_saddleItem = null;
				}
				else
				{
					EnsureRideController(((Component)tameable).gameObject, component, tameable);
				}
			}
		}

		private static Recipe CreateWhistleRecipe(ObjectDB objectDb, ItemDrop whistle)
		{
			Recipe val = ScriptableObject.CreateInstance<Recipe>();
			((Object)val).name = "Recipe_FehuWhistle";
			val.m_item = whistle;
			val.m_amount = 1;
			val.m_enabled = true;
			val.m_minStationLevel = 1;
			val.m_resources = (Requirement[])(object)new Requirement[3]
			{
				Requirement(objectDb, "BoneFragments", 2),
				Requirement(objectDb, "DeerHide", 1),
				Requirement(objectDb, "Resin", 1)
			};
			return val;
		}

		private static Requirement Requirement(ObjectDB objectDb, string prefabName, int amount)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_002d: Expected O, but got Unknown
			Requirement val = new Requirement();
			GameObject itemPrefab = objectDb.GetItemPrefab(prefabName);
			val.m_resItem = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			val.m_amount = amount;
			val.m_recover = true;
			return val;
		}

		private static int StableHash(string text)
		{
			int num = 5381;
			foreach (char c in text)
			{
				num = ((num << 5) + num) ^ c;
			}
			return num;
		}
	}
	internal static class ConfigSync
	{
		private static bool _registered;

		private static bool _applyingRemote;

		public static void HookSettings()
		{
			Plugin.EnableDeerTaming.SettingChanged += delegate
			{
				SendToAll();
			};
			Plugin.DeerTamingFoods.SettingChanged += delegate
			{
				SendToAll();
			};
			Plugin.MinStarsToRide.SettingChanged += delegate
			{
				SendToAll();
			};
			Plugin.EnableWhistle.SettingChanged += delegate
			{
				SendToAll();
			};
			Plugin.WhistleRange.SettingChanged += delegate
			{
				SendToAll();
			};
			Plugin.OnlyOwnerCanSummon.SettingChanged += delegate
			{
				SendToAll();
			};
		}

		public static void Register()
		{
			if (!_registered && ZRoutedRpc.instance != null)
			{
				_registered = true;
				ZRoutedRpc.instance.Register<string>("FehuMounts_ConfigSync", (Action<long, string>)Receive);
				ZRoutedRpc instance = ZRoutedRpc.instance;
				instance.m_onNewPeer = (Action<long>)Delegate.Combine(instance.m_onNewPeer, (Action<long>)delegate(long peerId)
				{
					SendToPeer(peerId);
				});
				SendToAll();
			}
		}

		private static void Receive(long sender, string payload)
		{
			if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer())
			{
				return;
			}
			string[] array = payload.Split('|');
			if (array.Length != 6)
			{
				return;
			}
			try
			{
				_applyingRemote = true;
				Plugin.EnableDeerTaming.Value = bool.Parse(array[0]);
				Plugin.DeerTamingFoods.Value = Encoding.UTF8.GetString(Convert.FromBase64String(array[1]));
				Plugin.MinStarsToRide.Value = int.Parse(array[2]);
				Plugin.EnableWhistle.Value = bool.Parse(array[3]);
				Plugin.WhistleRange.Value = float.Parse(array[4], CultureInfo.InvariantCulture);
				Plugin.OnlyOwnerCanSummon.Value = bool.Parse(array[5]);
			}
			finally
			{
				_applyingRemote = false;
			}
		}

		private static void SendToPeer(long peerId)
		{
			if (CanSend())
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(peerId, "FehuMounts_ConfigSync", new object[1] { Payload() });
			}
		}

		private static void SendToAll()
		{
			if (CanSend())
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "FehuMounts_ConfigSync", new object[1] { Payload() });
			}
		}

		private static bool CanSend()
		{
			if (!_applyingRemote && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				return ZRoutedRpc.instance != null;
			}
			return false;
		}

		private static string Payload()
		{
			string text = Convert.ToBase64String(Encoding.UTF8.GetBytes(Plugin.DeerTamingFoods.Value));
			return string.Join("|", Plugin.EnableDeerTaming.Value.ToString(), text, Plugin.MinStarsToRide.Value.ToString(), Plugin.EnableWhistle.Value.ToString(), Plugin.WhistleRange.Value.ToString(CultureInfo.InvariantCulture), Plugin.OnlyOwnerCanSummon.Value.ToString());
		}
	}
	[HarmonyPatch(typeof(ZNet), "Awake")]
	internal static class ZNetAwakePatch
	{
		private static void Postfix()
		{
			ConfigSync.Register();
		}
	}
	internal readonly struct MountTier
	{
		public float SpeedMultiplier { get; }

		public float StaminaMultiplier { get; }

		public float StaminaDrainMultiplier { get; }

		public bool LegendaryRecall { get; }

		public MountTier(float speedMultiplier, float staminaMultiplier, float staminaDrainMultiplier, bool legendaryRecall)
		{
			SpeedMultiplier = speedMultiplier;
			StaminaMultiplier = staminaMultiplier;
			StaminaDrainMultiplier = staminaDrainMultiplier;
			LegendaryRecall = legendaryRecall;
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class ObjectDbAwakePatch
	{
		private static void Postfix(ObjectDB __instance)
		{
			Plugin.RegisterWhistle(__instance);
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetSceneAwakePatch
	{
		private static void Postfix(ZNetScene __instance)
		{
			Plugin.ConfigureDeerPrefab(__instance);
			Plugin.RegisterWhistleScenePrefab(__instance);
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "GetPrefab", new Type[] { typeof(string) })]
	internal static class ZNetSceneGetPrefabPatch
	{
		private static void Postfix(string name, ref GameObject __result)
		{
			if ((Object)(object)__result == (Object)null && name == "FehuWhistle" && (Object)(object)ObjectDB.instance != (Object)null)
			{
				__result = ObjectDB.instance.GetItemPrefab("FehuWhistle");
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Awake")]
	internal static class CharacterAwakePatch
	{
		private static void Postfix(Character __instance)
		{
			if (Plugin.IsDeer(__instance))
			{
				Plugin.ConfigureDeer(((Component)__instance).gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "SetLevel")]
	internal static class CharacterSetLevelPatch
	{
		private static void Postfix(Character __instance)
		{
			if (Plugin.IsDeer(__instance))
			{
				Sadle component = ((Component)__instance).GetComponent<Sadle>();
				if ((Object)(object)component != (Object)null)
				{
					Plugin.ApplyTierStats(component, __instance);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Sadle), "IsValid")]
	internal static class SadleIsValidPatch
	{
		private static bool Prefix(Sadle __instance, ref bool __result)
		{
			Character character = __instance.GetCharacter();
			Tameable tameable = __instance.GetTameable();
			if (!Plugin.IsDeer(character))
			{
				return true;
			}
			__result = (Object)(object)tameable != (Object)null && tameable.IsTamed() && Plugin.CanRide(character);
			return false;
		}
	}
	[HarmonyPatch(typeof(Sadle), "GetHoverText")]
	internal static class SadleHoverTextPatch
	{
		private static bool Prefix(Sadle __instance, ref string __result)
		{
			Character character = __instance.GetCharacter();
			if (!Plugin.IsDeer(character))
			{
				return true;
			}
			Tameable tameable = __instance.GetTameable();
			if ((Object)(object)tameable == (Object)null || !tameable.IsTamed())
			{
				__result = "";
				return false;
			}
			__result = (Plugin.CanRide(character) ? "[<color=yellow><b>$KEY_Use</b></color>] Ride Deer" : "");
			return false;
		}
	}
	[HarmonyPatch(typeof(Sadle), "Interact")]
	internal static class SadleInteractPatch
	{
		private static bool Prefix(Sadle __instance, Humanoid character, ref bool __result)
		{
			Character character2 = __instance.GetCharacter();
			if (!Plugin.IsDeer(character2))
			{
				return true;
			}
			if (Plugin.CanRide(character2) && __instance.IsValid())
			{
				Plugin.StoreOwnerIfMissing(((Component)character2).GetComponent<ZNetView>(), (Player?)(object)((character is Player) ? character : null));
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Tameable), "Command")]
	internal static class TameableCommandPatch
	{
		private static void Prefix(Tameable __instance, Humanoid user)
		{
			if (Plugin.IsDeer(((Component)__instance).GetComponent<Character>()))
			{
				Plugin.StoreOwnerIfMissing(((Component)__instance).GetComponent<ZNetView>(), (Player?)(object)((user is Player) ? user : null));
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "Interact")]
	internal static class TameableInteractPatch
	{
		private static void Prefix(Tameable __instance, Humanoid user)
		{
			if (Plugin.IsDeer(((Component)__instance).GetComponent<Character>()))
			{
				Plugin.StoreOwnerIfMissing(((Component)__instance).GetComponent<ZNetView>(), (Player?)(object)((user is Player) ? user : null));
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "Update")]
	internal static class TameableUpdatePatch
	{
		private static void Postfix(Tameable __instance)
		{
			Plugin.UpdateRideController(__instance);
		}
	}
	[HarmonyPatch(typeof(Humanoid), "UseItem")]
	internal static class WhistleUsePatch
	{
		private static bool Prefix(Humanoid __instance, Inventory inventory, ItemData item)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val == null || !Plugin.IsWhistle(item))
			{
				return true;
			}
			Plugin.UseWhistle(val);
			return false;
		}
	}
	[HarmonyPatch(typeof(Sadle), "UpdateRiding")]
	internal static class SadleUpdateRidingPatch
	{
		private static void Prefix(Sadle __instance)
		{
			Character character = __instance.GetCharacter();
			if (Plugin.IsDeer(character))
			{
				Plugin.ApplyTierStats(__instance, character);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "GetJogSpeedFactor")]
	internal static class CharacterJogSpeedPatch
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			if (Plugin.IsDeer(__instance) && __instance.HaveRider())
			{
				__result *= Plugin.GetTier(__instance).SpeedMultiplier;
			}
		}
	}
	[HarmonyPatch(typeof(Character), "GetRunSpeedFactor")]
	internal static class CharacterRunSpeedPatch
	{
		private static void Postfix(Character __instance, ref float __result)
		{
			if (Plugin.IsDeer(__instance) && __instance.HaveRider())
			{
				__result *= Plugin.GetTier(__instance).SpeedMultiplier;
			}
		}
	}
}