Decompiled source of PassiveWolves v2.2.0

ChineseCanFly.PassiveWolves.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ChineseCanFly.PassiveWolves")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ChineseCanFly.PassiveWolves")]
[assembly: AssemblyTitle("ChineseCanFly.PassiveWolves")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ChineseCanFly.PassiveWolves
{
	[BepInPlugin("ChineseCanFly.PassiveWolves", "Passive Wolves", "2.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		private sealed class Entry
		{
			public string Prefab;

			public string Display;

			public float Alert;

			public float Chase;

			public bool Cleared;
		}

		public const string Guid = "ChineseCanFly.PassiveWolves";

		private static Plugin _instance;

		private static Harmony _harmony;

		private static readonly HashSet<string> VanillaTames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Boar", "Boar_piggy", "Wolf", "Wolf_cub", "Lox", "Lox_calf", "Chicken", "Hen", "Asksvin", "Asksvin_calf" };

		private ConfigEntry<KeyboardShortcut> _hotkey;

		private ConfigEntry<bool> _startPassive;

		private ConfigEntry<float> _maxDistance;

		private ConfigEntry<float> _scanInterval;

		private ConfigEntry<bool> _vanilla;

		private ConfigEntry<string> _custom;

		private ConfigEntry<string> _only;

		private ConfigEntry<string> _never;

		private ConfigEntry<bool> _logPerf;

		private ConfigEntry<bool> _hudShow;

		private ConfigEntry<float> _hudX;

		private ConfigEntry<float> _hudY;

		private ConfigEntry<int> _hudFont;

		private ConfigEntry<bool> _hudPrefabNames;

		private static ConfigEntry<float> _followDistance;

		private static ConfigEntry<float> _chaseRange;

		private static ConfigEntry<string> _ignoreTargets;

		private static ConfigEntry<bool> _assistOnly;

		private static ConfigEntry<bool> _ignoreTamingTargets;

		private static readonly List<string> IgnoreList = new List<string>();

		private static string _ignoreRaw;

		private static readonly Dictionary<MonsterAI, float> ChaseTracked = new Dictionary<MonsterAI, float>();

		private static readonly List<MonsterAI> ChaseDrop = new List<MonsterAI>();

		private static readonly Dictionary<Character, string> NameCache = new Dictionary<Character, string>();

		private static readonly Dictionary<MonsterAI, Entry> Tracked = new Dictionary<MonsterAI, Entry>();

		private static readonly List<MonsterAI> Drop = new List<MonsterAI>();

		private static readonly Dictionary<string, int> ScanCounts = new Dictionary<string, int>();

		private static readonly Dictionary<string, int> LastCounts = new Dictionary<string, int>();

		private static readonly Dictionary<string, string> DisplayCache = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private static readonly FieldInfo TargetCreature = typeof(MonsterAI).GetField("m_targetCreature", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo TargetStatic = typeof(MonsterAI).GetField("m_targetStatic", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly List<string> CustomList = new List<string>();

		private static readonly List<string> OnlyList = new List<string>();

		private static readonly List<string> NeverList = new List<string>();

		private static string _customRaw;

		private static string _onlyRaw;

		private static string _neverRaw;

		private static Dictionary<string, string> _lang = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

		private static string _languageName = "English";

		private static bool _passive;

		private float _scanTimer;

		private double _perfTotalMs;

		private double _perfMaxMs;

		private int _perfScans;

		private int _perfLastCount;

		private string _hudText = "";

		private int _hudTotal;

		private GUIStyle _boxStyle;

		private GUIStyle _textStyle;

		private int _styleFontSize = -1;

		private static MethodInfo _localizeMethod;

		private static object _localizeInstance;

		internal static float FollowDistanceValue
		{
			get
			{
				if (_followDistance == null)
				{
					return 3f;
				}
				return _followDistance.Value;
			}
		}

		private void Awake()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Expected O, but got Unknown
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Expected O, but got Unknown
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Expected O, but got Unknown
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Expected O, but got Unknown
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Expected O, but got Unknown
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Expected O, but got Unknown
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Expected O, but got Unknown
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Expected O, but got Unknown
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_032f: Expected O, but got Unknown
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Expected O, but got Unknown
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Expected O, but got Unknown
			//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Expected O, but got Unknown
			//IL_0422: Unknown result type (might be due to invalid IL or missing references)
			//IL_042c: Expected O, but got Unknown
			//IL_0457: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Expected O, but got Unknown
			//IL_048c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0496: Expected O, but got Unknown
			//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d1: Unknown result type (might be due to invalid IL or missing references)
			_instance = this;
			LoadLanguage();
			_hotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "Toggle Hotkey", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), new ConfigDescription(T("ToggleHotkey", "Key that switches the affected tamed creatures between fighting and passive."), (AcceptableValueBase)null, Array.Empty<object>()));
			_startPassive = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Start Passive", false, new ConfigDescription(T("StartPassive", "Default is off, so every tame fights normally until you press the hotkey."), (AcceptableValueBase)null, Array.Empty<object>()));
			_scanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Scan Interval", 1f, new ConfigDescription(T("ScanInterval", "Seconds between checks for newly tamed or newly loaded creatures."), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 5f), Array.Empty<object>()));
			_maxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Max Distance", 0f, new ConfigDescription(T("MaxDistance", "Calm radius (m): 0 = no limit, every tamed animal stays peaceful. A number = only animals inside the circle stay peaceful."), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 500f), Array.Empty<object>()));
			_vanilla = ((BaseUnityPlugin)this).Config.Bind<bool>("Scope", "Affect Vanilla Tames", true, new ConfigDescription(T("AffectVanilla", "Affect the game's own tameable animals: boar, wolf, lox, chicken and asksvin."), (AcceptableValueBase)null, Array.Empty<object>()));
			_custom = ((BaseUnityPlugin)this).Config.Bind<string>("Scope", "Custom Mod Prefabs", "", new ConfigDescription(T("CustomPrefabs", "For animals added by other mods: prefab names, comma separated."), (AcceptableValueBase)null, Array.Empty<object>()));
			_only = ((BaseUnityPlugin)this).Config.Bind<string>("Scope", "Only These Prefabs", "", new ConfigDescription(T("OnlyPrefabs", "Optional strict whitelist. When set, ONLY these are affected."), (AcceptableValueBase)null, Array.Empty<object>()));
			_never = ((BaseUnityPlugin)this).Config.Bind<string>("Scope", "Never These Prefabs", "", new ConfigDescription(T("NeverPrefabs", "Comma separated prefab names that are never affected."), (AcceptableValueBase)null, Array.Empty<object>()));
			_logPerf = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "Log Performance", false, new ConfigDescription(T("LogPerformance", "Every 60 scans, write average and worst scan time to the log."), (AcceptableValueBase)null, Array.Empty<object>()));
			_hudShow = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "Show HUD", true, new ConfigDescription(T("HudShow", "Show the calm panel at the left edge while calm mode is on."), (AcceptableValueBase)null, Array.Empty<object>()));
			_hudX = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "HUD X (%)", 1f, new ConfigDescription(T("HudX", "Panel distance from the left edge, in percent of screen width."), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			_hudY = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "HUD Y (%)", 45f, new ConfigDescription(T("HudY", "Panel distance from the top edge, in percent of screen height."), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			_hudFont = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "Font Size", 16, new ConfigDescription(T("HudFont", "Panel text size in pixels."), (AcceptableValueBase)(object)new AcceptableValueRange<int>(8, 40), Array.Empty<object>()));
			_hudPrefabNames = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "Show Prefab Names", false, new ConfigDescription(T("HudPrefabNames", "Show raw prefab names instead of translated creature names."), (AcceptableValueBase)null, Array.Empty<object>()));
			_followDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Behaviour", "Follow Distance", 3f, new ConfigDescription(T("FollowDistance", "How close (m) a following tame may get before it stops. 3 = the game's own behaviour; larger numbers keep the pack further away. Always on, no hotkey."), (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 30f), Array.Empty<object>()));
			_chaseRange = ((BaseUnityPlugin)this).Config.Bind<float>("Behaviour", "Chase Range", 0f, new ConfigDescription(T("ChaseRange", "Give up a fight when the target is further than this (m) away from you. 0 = the game's own behaviour. Does not apply while calm mode is on (that already holds everything)."), (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			_ignoreTargets = ((BaseUnityPlugin)this).Config.Bind<string>("Behaviour", "Ignore Targets", "", new ConfigDescription(T("IgnoreTargets", "Prefab names these tames never treat as enemies, comma separated, e.g. Deer,Boar,Rabbit. Empty = the game's own behaviour."), (AcceptableValueBase)null, Array.Empty<object>()));
			_ignoreTamingTargets = ((BaseUnityPlugin)this).Config.Bind<bool>("Behaviour", "Ignore Taming Targets", true, new ConfigDescription(T("IgnoreTamingTargets", "Never attack a wild creature that can still be tamed (its taming has not finished), so the pack stops killing the boar or wolf you are taming."), (AcceptableValueBase)null, Array.Empty<object>()));
			_assistOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("Behaviour", "Assist Only", false, new ConfigDescription(T("AssistOnly", "Only fight back against something that is already attacking you or one of your tames. Off = the pack picks its own fights."), (AcceptableValueBase)null, Array.Empty<object>()));
			_passive = _startPassive.Value;
			ApplyPatches();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Passive Wolves 2.2.0 loaded. Language: " + _languageName + ", hotkey " + ((object)_hotkey.Value/*cast due to .constrained prefix*/).ToString()));
		}

		private void ApplyPatches()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			try
			{
				_harmony = new Harmony("ChineseCanFly.PassiveWolves");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Harmony unavailable, behaviour patches disabled: " + ex));
				return;
			}
			try
			{
				_harmony.PatchAll(typeof(PatchFollowDistance));
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Patch applied: follow distance.");
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Follow distance patch failed, using the game's 3 m: " + ex2));
			}
			try
			{
				_harmony.PatchAll(typeof(PatchIsEnemy));
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Patch applied: target filters.");
			}
			catch (Exception ex3)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Target filter patch failed, targeting stays vanilla: " + ex3));
			}
		}

		private void Update()
		{
			//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)
			try
			{
				KeyboardShortcut value = _hotkey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					SetPassive(!_passive, announce: true);
				}
				_scanTimer += Time.deltaTime;
				float num = Mathf.Max(0.25f, _scanInterval.Value);
				if (_scanTimer >= num)
				{
					_scanTimer = 0f;
					SyncLists();
					if (_passive)
					{
						Apply(announce: false);
					}
					else
					{
						MaintainChase();
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Passive Wolves update failed: " + ex));
			}
		}

		private void OnGUI()
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			if (!_passive || _hudTotal <= 0 || _hudShow == null || !_hudShow.Value)
			{
				return;
			}
			try
			{
				int value = _hudFont.Value;
				if (_boxStyle == null || _styleFontSize != value)
				{
					_boxStyle = new GUIStyle(GUI.skin.box);
					_textStyle = new GUIStyle(GUI.skin.label);
					_textStyle.fontSize = value;
					_textStyle.alignment = (TextAnchor)0;
					_textStyle.wordWrap = false;
					_styleFontSize = value;
				}
				float num = (float)Screen.width * Mathf.Clamp01(_hudX.Value / 100f);
				float num2 = (float)Screen.height * Mathf.Clamp01(_hudY.Value / 100f);
				Vector2 val = _textStyle.CalcSize(new GUIContent(_hudText));
				Rect val2 = default(Rect);
				((Rect)(ref val2))..ctor(num, num2, val.x + 16f, val.y + 12f);
				GUI.Box(val2, GUIContent.none, _boxStyle);
				GUI.Label(new Rect(((Rect)(ref val2)).x + 8f, ((Rect)(ref val2)).y + 6f, val.x, val.y), _hudText, _textStyle);
			}
			catch
			{
			}
		}

		private void SetPassive(bool on, bool announce)
		{
			_passive = on;
			if (on)
			{
				RestoreChase();
				Apply(announce);
				return;
			}
			Restore();
			if (announce)
			{
				Announce(T("MsgOff", "Tames: fighting again"));
			}
		}

		private void Apply(bool announce)
		{
			long timestamp = Stopwatch.GetTimestamp();
			Player localPlayer = Player.m_localPlayer;
			float value = _maxDistance.Value;
			bool value2 = _vanilla.Value;
			SyncLists();
			ScanCounts.Clear();
			int num = 0;
			List<Character> allCharacters = Character.GetAllCharacters();
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if (!Qualifies(val, localPlayer, value, value2))
				{
					continue;
				}
				MonsterAI component = ((Component)val).GetComponent<MonsterAI>();
				if (!((Object)(object)component == (Object)null))
				{
					if (!Tracked.TryGetValue(component, out var value3))
					{
						string text = PrefabName(val);
						value3 = new Entry
						{
							Prefab = text,
							Display = (VanillaTames.Contains(text) ? DisplayName(val) : text),
							Alert = component.m_alertRange,
							Chase = component.m_maxChaseDistance
						};
						Tracked[component] = value3;
						DisplayCache[value3.Prefab] = value3.Display;
					}
					if (!value3.Cleared || component.m_alertRange != 0f || component.m_maxChaseDistance != 0f)
					{
						component.m_alertRange = 0f;
						component.m_maxChaseDistance = 0f;
						ClearTarget(component);
						value3.Cleared = true;
					}
					ScanCounts.TryGetValue(value3.Prefab, out var value4);
					ScanCounts[value3.Prefab] = value4 + 1;
					num++;
				}
			}
			Drop.Clear();
			foreach (KeyValuePair<MonsterAI, Entry> item in Tracked)
			{
				MonsterAI key = item.Key;
				bool flag = false;
				if ((Object)(object)key != (Object)null)
				{
					Character component2 = ((Component)key).GetComponent<Character>();
					flag = (Object)(object)component2 != (Object)null && Qualifies(component2, localPlayer, value, value2);
				}
				if (!flag)
				{
					if ((Object)(object)key != (Object)null)
					{
						key.m_alertRange = item.Value.Alert;
						key.m_maxChaseDistance = item.Value.Chase;
					}
					Drop.Add(key);
				}
			}
			for (int j = 0; j < Drop.Count; j++)
			{
				Tracked.Remove(Drop[j]);
			}
			if (_hudTotal != num || CountsChanged())
			{
				RebuildHud();
			}
			if (announce)
			{
				Announce(string.Format(T("MsgOn", "Tames: passive now ({0})"), num));
			}
			RecordPerf((double)(Stopwatch.GetTimestamp() - timestamp) * 1000.0 / (double)Stopwatch.Frequency, num);
		}

		private bool CountsChanged()
		{
			if (ScanCounts.Count != LastCounts.Count)
			{
				return true;
			}
			foreach (KeyValuePair<string, int> scanCount in ScanCounts)
			{
				if (!LastCounts.TryGetValue(scanCount.Key, out var value) || value != scanCount.Value)
				{
					return true;
				}
			}
			return false;
		}

		private void RebuildHud()
		{
			LastCounts.Clear();
			List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>(ScanCounts.Count);
			foreach (KeyValuePair<string, int> scanCount in ScanCounts)
			{
				LastCounts[scanCount.Key] = scanCount.Value;
				list.Add(scanCount);
			}
			list.Sort(delegate(KeyValuePair<string, int> a, KeyValuePair<string, int> b)
			{
				int num2 = b.Value.CompareTo(a.Value);
				return (num2 == 0) ? string.Compare(a.Key, b.Key, StringComparison.OrdinalIgnoreCase) : num2;
			});
			_hudTotal = 0;
			StringBuilder stringBuilder = new StringBuilder();
			for (int num = 0; num < list.Count; num++)
			{
				string key = list[num].Key;
				int value = list[num].Value;
				_hudTotal += value;
				stringBuilder.Append(HudName(key)).Append(" x").Append(value)
					.Append('\n');
			}
			string text = string.Format(T("HudTitle", "Calm {0}"), _hudTotal);
			if (stringBuilder.Length > 0)
			{
				stringBuilder.Length--;
			}
			_hudText = text + "\n" + stringBuilder;
		}

		private string HudName(string prefab)
		{
			if (_hudPrefabNames.Value)
			{
				return prefab;
			}
			if (DisplayCache.TryGetValue(prefab, out var value))
			{
				return value;
			}
			return prefab;
		}

		private static string DisplayName(Character c)
		{
			try
			{
				string text = Localize(c.m_name);
				if (!string.IsNullOrEmpty(text) && text != c.m_name)
				{
					return text;
				}
			}
			catch
			{
			}
			return PrefabName(c);
		}

		private static string Localize(string token)
		{
			if (_localizeMethod == null && _localizeInstance == null)
			{
				Type type = FindLocalizationType();
				if (type != null)
				{
					PropertyInfo[] properties = type.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					for (int i = 0; i < properties.Length; i++)
					{
						if (!(properties[i].PropertyType != type))
						{
							try
							{
								_localizeInstance = properties[i].GetValue(null);
							}
							catch
							{
							}
							if (_localizeInstance != null)
							{
								break;
							}
						}
					}
					_localizeMethod = type.GetMethod("Localize", new Type[1] { typeof(string) });
				}
			}
			if (_localizeMethod == null || _localizeInstance == null)
			{
				return token;
			}
			try
			{
				string text = (string)_localizeMethod.Invoke(_localizeInstance, new object[1] { token });
				return string.IsNullOrEmpty(text) ? token : text;
			}
			catch
			{
				return token;
			}
		}

		private static Type FindLocalizationType()
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type[] types;
				try
				{
					types = assemblies[i].GetTypes();
				}
				catch
				{
					continue;
				}
				for (int j = 0; j < types.Length; j++)
				{
					if (types[j].Name == "Localization")
					{
						return types[j];
					}
				}
			}
			return null;
		}

		private void Restore()
		{
			foreach (KeyValuePair<MonsterAI, Entry> item in Tracked)
			{
				MonsterAI key = item.Key;
				if (!((Object)(object)key == (Object)null))
				{
					key.m_alertRange = item.Value.Alert;
					key.m_maxChaseDistance = item.Value.Chase;
				}
			}
			Tracked.Clear();
			ScanCounts.Clear();
			LastCounts.Clear();
			_hudTotal = 0;
			_hudText = "";
		}

		private bool Qualifies(Character c, Player player, float maxDist, bool vanilla)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)c == (Object)null || !c.IsTamed() || c.IsDead())
			{
				return false;
			}
			string text = PrefabName(c);
			if (Contains(NeverList, text))
			{
				return false;
			}
			if (OnlyList.Count > 0)
			{
				if (!Contains(OnlyList, text))
				{
					return false;
				}
			}
			else if ((!vanilla || !VanillaTames.Contains(text)) && !Contains(CustomList, text))
			{
				return false;
			}
			if (maxDist > 0f)
			{
				if ((Object)(object)player == (Object)null)
				{
					return false;
				}
				if (Vector3.SqrMagnitude(((Component)c).transform.position - ((Component)player).transform.position) > maxDist * maxDist)
				{
					return false;
				}
			}
			return true;
		}

		internal static bool InScopePrefab(Character c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return false;
			}
			string text = PrefabNameCached(c);
			if (Contains(NeverList, text))
			{
				return false;
			}
			if (OnlyList.Count > 0)
			{
				return Contains(OnlyList, text);
			}
			if (!((Object)(object)_instance != (Object)null) || _instance._vanilla == null || !_instance._vanilla.Value || !VanillaTames.Contains(text))
			{
				return Contains(CustomList, text);
			}
			return true;
		}

		internal static float StopDistanceFor(BaseAI ai)
		{
			float followDistanceValue = FollowDistanceValue;
			if ((Object)(object)ai == (Object)null || followDistanceValue <= 3.05f)
			{
				return 3f;
			}
			Character component = ((Component)ai).GetComponent<Character>();
			if ((Object)(object)component == (Object)null || !component.IsTamed() || !InScopePrefab(component))
			{
				return 3f;
			}
			return followDistanceValue;
		}

		private static bool IgnoreFeatureActive()
		{
			if (IgnoreList.Count > 0)
			{
				return true;
			}
			if (_ignoreTamingTargets != null && _ignoreTamingTargets.Value)
			{
				return true;
			}
			if (_assistOnly != null && _assistOnly.Value)
			{
				return true;
			}
			return false;
		}

		internal static bool ShouldBlockEnemy(Character a, Character b)
		{
			if ((Object)(object)a == (Object)null || (Object)(object)b == (Object)null)
			{
				return false;
			}
			if (!IgnoreFeatureActive())
			{
				return false;
			}
			if (!a.IsTamed())
			{
				return false;
			}
			if (b.IsPlayer())
			{
				return false;
			}
			if (!InScopePrefab(a))
			{
				return false;
			}
			if (IgnoreList.Count > 0 && Contains(IgnoreList, PrefabNameCached(b)))
			{
				return true;
			}
			if (_ignoreTamingTargets != null && _ignoreTamingTargets.Value && !b.IsTamed() && (Object)(object)((Component)b).GetComponent<Tameable>() != (Object)null && !IsThreatening(b))
			{
				return true;
			}
			if (_assistOnly != null && _assistOnly.Value && !IsThreatening(b))
			{
				return true;
			}
			return false;
		}

		private static bool IsThreatening(Character b)
		{
			MonsterAI component = ((Component)b).GetComponent<MonsterAI>();
			if ((Object)(object)component == (Object)null || TargetCreature == null)
			{
				return false;
			}
			object? value = TargetCreature.GetValue(component);
			Character val = (Character)((value is Character) ? value : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (!val.IsPlayer())
			{
				return val.IsTamed();
			}
			return true;
		}

		private static string PrefabNameCached(Character c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return "";
			}
			if (NameCache.TryGetValue(c, out var value))
			{
				return value;
			}
			value = PrefabName(c);
			if (NameCache.Count > 1000)
			{
				NameCache.Clear();
			}
			NameCache[c] = value;
			return value;
		}

		private void MaintainChase()
		{
			float num = ((_chaseRange != null) ? _chaseRange.Value : 0f);
			if (num <= 0f)
			{
				RestoreChase();
				return;
			}
			List<Character> allCharacters = Character.GetAllCharacters();
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val = allCharacters[i];
				if ((Object)(object)val == (Object)null || !val.IsTamed() || val.IsDead() || !InScopePrefab(val))
				{
					continue;
				}
				MonsterAI component = ((Component)val).GetComponent<MonsterAI>();
				if (!((Object)(object)component == (Object)null))
				{
					if (!ChaseTracked.ContainsKey(component))
					{
						ChaseTracked[component] = component.m_alertRange;
					}
					if (component.m_alertRange != num)
					{
						component.m_alertRange = num;
					}
				}
			}
			ChaseDrop.Clear();
			foreach (KeyValuePair<MonsterAI, float> item in ChaseTracked)
			{
				MonsterAI key = item.Key;
				bool flag = false;
				if ((Object)(object)key != (Object)null)
				{
					Character component2 = ((Component)key).GetComponent<Character>();
					flag = (Object)(object)component2 != (Object)null && component2.IsTamed() && !component2.IsDead() && InScopePrefab(component2);
				}
				if (!flag)
				{
					if ((Object)(object)key != (Object)null)
					{
						key.m_alertRange = item.Value;
					}
					ChaseDrop.Add(key);
				}
			}
			for (int j = 0; j < ChaseDrop.Count; j++)
			{
				ChaseTracked.Remove(ChaseDrop[j]);
			}
		}

		private static void RestoreChase()
		{
			if (ChaseTracked.Count == 0)
			{
				return;
			}
			foreach (KeyValuePair<MonsterAI, float> item in ChaseTracked)
			{
				MonsterAI key = item.Key;
				if ((Object)(object)key != (Object)null)
				{
					key.m_alertRange = item.Value;
				}
			}
			ChaseTracked.Clear();
		}

		private void SyncLists()
		{
			if (!string.Equals(_customRaw, _custom.Value, StringComparison.Ordinal))
			{
				_customRaw = _custom.Value;
				Rebuild(CustomList, _customRaw);
			}
			if (!string.Equals(_onlyRaw, _only.Value, StringComparison.Ordinal))
			{
				_onlyRaw = _only.Value;
				Rebuild(OnlyList, _onlyRaw);
			}
			if (!string.Equals(_neverRaw, _never.Value, StringComparison.Ordinal))
			{
				_neverRaw = _never.Value;
				Rebuild(NeverList, _neverRaw);
			}
			if (_ignoreTargets != null && !string.Equals(_ignoreRaw, _ignoreTargets.Value, StringComparison.Ordinal))
			{
				_ignoreRaw = _ignoreTargets.Value;
				Rebuild(IgnoreList, _ignoreRaw);
			}
		}

		private static void Rebuild(List<string> list, string raw)
		{
			list.Clear();
			if (string.IsNullOrEmpty(raw))
			{
				return;
			}
			string[] array = raw.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					list.Add(text);
				}
			}
		}

		private static bool Contains(List<string> list, string name)
		{
			for (int i = 0; i < list.Count; i++)
			{
				if (string.Equals(list[i], name, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static string PrefabName(Character c)
		{
			string text = ((Object)((Component)c).gameObject).name;
			if (text.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				text = text.Substring(0, text.Length - 7);
			}
			return text.Trim();
		}

		private static void ClearTarget(MonsterAI ai)
		{
			try
			{
				if (TargetCreature != null)
				{
					TargetCreature.SetValue(ai, null);
				}
				if (TargetStatic != null)
				{
					TargetStatic.SetValue(ai, null);
				}
			}
			catch
			{
			}
		}

		private void RecordPerf(double ms, int count)
		{
			_perfScans++;
			_perfTotalMs += ms;
			_perfLastCount = count;
			if (ms > _perfMaxMs)
			{
				_perfMaxMs = ms;
			}
			if (_perfScans >= 60)
			{
				if (_logPerf != null && _logPerf.Value)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)$"perf: {_perfScans} scans, avg {_perfTotalMs / (double)_perfScans:F3} ms, max {_perfMaxMs:F3} ms, {_perfLastCount} tame(s) held, {Tracked.Count} tracked");
				}
				_perfScans = 0;
				_perfTotalMs = 0.0;
				_perfMaxMs = 0.0;
			}
		}

		private void LoadLanguage()
		{
			try
			{
				string text = PlayerPrefs.GetString("language", "English");
				_languageName = (string.IsNullOrEmpty(text) ? "English" : text);
				string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
				string path = Path.Combine(directoryName, "PassiveWolves." + _languageName + ".yml");
				if (!File.Exists(path))
				{
					path = Path.Combine(directoryName, "PassiveWolves.English.yml");
				}
				if (!File.Exists(path))
				{
					return;
				}
				string[] array = File.ReadAllLines(path, Encoding.UTF8);
				for (int i = 0; i < array.Length; i++)
				{
					string text2 = array[i].Trim();
					if (text2.Length == 0 || text2.StartsWith("#"))
					{
						continue;
					}
					int num = text2.IndexOf(':');
					if (num > 0)
					{
						string key = text2.Substring(0, num).Trim();
						string text3 = text2.Substring(num + 1).Trim();
						if (text3.Length >= 2 && text3[0] == '"' && text3[text3.Length - 1] == '"')
						{
							text3 = text3.Substring(1, text3.Length - 2).Replace("\\\"", "\"").Replace("\\n", "\n");
						}
						_lang[key] = text3;
					}
				}
			}
			catch
			{
			}
		}

		private static string T(string key, string fallback)
		{
			if (_lang.TryGetValue(key, out var value) && !string.IsNullOrEmpty(value))
			{
				return value;
			}
			return fallback;
		}

		private static void Announce(string text)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}
	}
	[HarmonyPatch(typeof(BaseAI), "Follow")]
	internal static class PatchFollowDistance
	{
		private static bool Prefix(BaseAI __instance, GameObject go)
		{
			//IL_002f: 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_003f: 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)
			try
			{
				if ((Object)(object)__instance == (Object)null || (Object)(object)go == (Object)null)
				{
					return true;
				}
				float num = Plugin.StopDistanceFor(__instance);
				if (num <= 3.05f)
				{
					return true;
				}
				Vector3 val = go.transform.position - ((Component)__instance).transform.position;
				if (((Vector3)(ref val)).sqrMagnitude < num * num)
				{
					__instance.StopMoving();
					return false;
				}
			}
			catch
			{
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[]
	{
		typeof(Character),
		typeof(Character)
	})]
	internal static class PatchIsEnemy
	{
		private static bool Prefix(Character a, Character b, ref bool __result)
		{
			try
			{
				if (Plugin.ShouldBlockEnemy(a, b))
				{
					__result = false;
					return false;
				}
			}
			catch
			{
			}
			return true;
		}
	}
}