Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PassiveWolves v2.2.0
ChineseCanFly.PassiveWolves.dll
Decompiled 2 weeks agousing 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; } } }