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 PlayerThreatLevel v1.2.1
PlayerThreatLevel.dll
Decompiled 11 hours 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.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using ConditionalConfigSync; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("PlayerThreatLevel")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.2.1.0")] [assembly: AssemblyInformationalVersion("1.2.1")] [assembly: AssemblyProduct("PlayerThreatLevel")] [assembly: AssemblyTitle("PlayerThreatLevel")] [assembly: AssemblyVersion("1.2.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PlayerThreatLevel { internal sealed class BossInfo { public readonly Biome Biome; public readonly string BiomeName; public readonly string BossName; public BossInfo(Biome biome, string biomeName, string bossName) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) Biome = biome; BiomeName = biomeName; BossName = bossName; } } [BepInPlugin("com.dreich.playerthreatlevel", "Player Threat Level", "1.2.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class PlayerThreatLevel : BaseUnityPlugin { public const string Guid = "com.dreich.playerthreatlevel"; public const string Name = "Player Threat Level"; public const string Version = "1.2.1"; internal const string ConfigSyncGuid = "_shudnal.ConditionalConfigSync"; internal static PlayerThreatLevel Instance; internal static ManualLogSource Log; internal static bool ConfigSyncAvailable; internal static readonly Dictionary<string, BossInfo> Bosses = new Dictionary<string, BossInfo> { { "defeated_eikthyr", new BossInfo((Biome)1, "Meadows", "Eikthyr") }, { "defeated_gdking", new BossInfo((Biome)8, "Black Forest", "The Elder") }, { "defeated_bonemass", new BossInfo((Biome)2, "Swamp", "Bonemass") }, { "defeated_dragon", new BossInfo((Biome)4, "Mountain", "Moder") }, { "defeated_goblinking", new BossInfo((Biome)16, "Plains", "Yagluth") }, { "defeated_queen", new BossInfo((Biome)512, "Mistlands", "The Queen") }, { "defeated_fader", new BossInfo((Biome)32, "Ashlands", "Fader") }, { "defeated_frozenking", new BossInfo((Biome)64, "Deep North", "Kall Fimbulbringer") } }; private static ConfigEntry<bool> ConfigLockedEntry; private static ConfigEntry<float> BaseFearRadiusEntry; private static ConfigEntry<float> FearRadiusPerLevelEntry; private static ConfigEntry<float> FearDurationEntry; private static ConfigEntry<bool> BossesImmuneEntry; private static ConfigEntry<bool> StarredImmuneEntry; private static ConfigEntry<bool> SeedFromDefeatedBossesEntry; private static ConfigEntry<bool> HostileIfAttackedEntry; private static ConfigEntry<float> HostileDurationEntry; private static ConfigEntry<float> FearImmunityAfterAttackEntry; private static ConfigEntry<bool> AlertWhenFleeingEntry; private static ConfigEntry<float> AllyCourageRadiusEntry; internal static ConfigEntry<bool> ShowMessages; internal static ConfigEntry<MessageType> MessageLocation; internal static ConfigEntry<string> LevelUpMessage; internal static ConfigEntry<string> MaxLevelMessage; private FileSystemWatcher watcher; private volatile bool reloadPending; private long lastChangeTicks; private long ignoreUntilTicks; private static readonly SortedDictionary<string, ConfigEntry<bool>> CreatureToggles = new SortedDictionary<string, ConfigEntry<bool>>(StringComparer.Ordinal); internal static float BaseFearRadius => BaseFearRadiusEntry.Value; internal static float FearRadiusPerLevel => FearRadiusPerLevelEntry.Value; internal static float FearDuration => FearDurationEntry.Value; internal static bool BossesImmune => BossesImmuneEntry.Value; internal static bool StarredImmune => StarredImmuneEntry.Value; internal static bool SeedFromDefeatedBosses => SeedFromDefeatedBossesEntry.Value; internal static bool HostileIfAttacked => HostileIfAttackedEntry.Value; internal static float HostileDuration => HostileDurationEntry.Value; internal static float FearImmunityAfterAttack => FearImmunityAfterAttackEntry.Value; internal static bool AlertWhenFleeing => AlertWhenFleeingEntry.Value; internal static float AllyCourageRadius => AllyCourageRadiusEntry.Value; private void Awake() { //IL_0242: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; ConfigSyncAvailable = Chainloader.PluginInfos.ContainsKey("_shudnal.ConditionalConfigSync"); if (ConfigSyncAvailable) { ConfigSyncCompat.Initialize("com.dreich.playerthreatlevel", "Player Threat Level", "1.2.1"); } else { Log.LogInfo((object)"ConditionalConfigSync not found; configuration will not be synced from the server."); } ConfigLockedEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Lock Configuration", true, "If on, the configuration is locked and can be changed by server admins only. Requires ConditionalConfigSync."); if (ConfigSyncAvailable) { ConfigSyncCompat.AddLockingConfigEntry(ConfigLockedEntry); } BaseFearRadiusEntry = BindShared("Fear", "BaseFearRadius", 12f, "Distance (m) at which monsters start fleeing at threat level 1."); FearRadiusPerLevelEntry = BindShared("Fear", "FearRadiusPerLevel", 4f, "Extra fear radius (m) for each threat level after the first."); FearDurationEntry = BindShared("Fear", "FearDuration", 6f, "Seconds a monster keeps running after it last sensed you."); BossesImmuneEntry = BindShared("Fear", "BossesImmune", defaultValue: true, "Bosses are never scared."); StarredImmuneEntry = BindShared("Fear", "StarredImmune", defaultValue: true, "Creatures with one or more stars are never scared."); HostileIfAttackedEntry = BindShared("Fear", "HostileIfAttacked", defaultValue: true, "If you attack a monster that fears you, it stops fleeing and fights back."); HostileDurationEntry = BindShared("Fear", "HostileDuration", 30f, "Seconds a monster stays unafraid of the player who last hit it. 0 means it never fears that player again."); FearImmunityAfterAttackEntry = BindShared("Fear", "FearImmunityAfterAttack", 20f, "Seconds a monster cannot become afraid of any player after any player hits it, even if a different player comes near. 0 disables."); AlertWhenFleeingEntry = BindShared("Fear", "AlertWhenFleeing", defaultValue: true, "Fleeing monsters show the red exclamation mark and play their alert sound, like deer do. Runs on the peer that owns the monster, so it is server-controlled."); AllyCourageRadiusEntry = BindShared("Fear", "AllyCourageRadius", 10f, "Distance (m) a frightened monster checks around itself for other living monsters of its own faction. If it finds any, it is no longer afraid. 0 disables the check."); SeedFromDefeatedBossesEntry = BindShared("Progress", "CheckDefeatedBosses", defaultValue: true, "On spawn, count bosses already defeated in this world toward your threat level."); ShowMessages = BindLocal("Messages", "ShowMessages", defaultValue: true, "Show a message when your threat level rises."); MessageLocation = BindLocal<MessageType>("Messages", "MessageLocation", (MessageType)2, "Where the message appears: Center or TopLeft."); LevelUpMessage = BindLocal("Messages", "LevelUpMessage", "Threat Level {level}\\nThe {biome} fears you", "Message shown when a boss kill raises your threat level. Placeholders: {level}, {max}, {biome}, {boss}. Use \\n for a line break. Leave empty to show nothing."); MaxLevelMessage = BindLocal("Messages", "MaxLevelMessage", "Threat Level {level}\\nAll of Valheim fears you", "Message shown instead when you reach the maximum threat level. Same placeholders. Leave empty to use LevelUpMessage."); SetupWatcher(); new Harmony("com.dreich.playerthreatlevel").PatchAll(); } internal static bool IsCreatureEnabled(string prefabName) { if (!string.IsNullOrEmpty(prefabName) && CreatureToggles.TryGetValue(prefabName, out var value)) { return value.Value; } return true; } internal static IEnumerable<string> DisabledCreatures() { foreach (KeyValuePair<string, ConfigEntry<bool>> creatureToggle in CreatureToggles) { if (!creatureToggle.Value.Value) { yield return creatureToggle.Key; } } } internal static void RegisterCreatures(IEnumerable<GameObject> prefabs) { if ((Object)(object)Instance == (Object)null || prefabs == null) { return; } SortedDictionary<string, bool> sortedDictionary = new SortedDictionary<string, bool>(StringComparer.Ordinal); foreach (GameObject prefab in prefabs) { if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab.GetComponent<MonsterAI>() == (Object)null) && !((Object)(object)prefab.GetComponent<Character>() == (Object)null) && !((Object)(object)prefab.GetComponent<Player>() != (Object)null)) { sortedDictionary[((Object)prefab).name] = true; } } ConfigFile config = ((BaseUnityPlugin)Instance).Config; bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; int num = 0; try { foreach (string key in sortedDictionary.Keys) { if (!CreatureToggles.ContainsKey(key)) { CreatureToggles[key] = Instance.BindShared("Creatures", key, defaultValue: true, "Creatures with this prefab name flee from you when your threat level is high enough. Server-controlled."); num++; } } } finally { config.SaveOnConfigSet = saveOnConfigSet; } if (num > 0) { config.Save(); Log.LogInfo((object)("Registered " + num + " creature toggles.")); } } private ConfigEntry<T> BindShared<T>(string section, string key, T defaultValue, string description) { ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, description); if (ConfigSyncAvailable) { ConfigSyncCompat.AddConfigEntry<T>(val, serverControlled: true); } return val; } private ConfigEntry<T> BindLocal<T>(string section, string key, T defaultValue, string description) { ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, description); if (ConfigSyncAvailable) { ConfigSyncCompat.AddConfigEntry<T>(val, serverControlled: false); } return val; } internal static bool IsSyncedFromServer() { if (ConfigSyncAvailable) { return ConfigSyncCompat.InitialSyncDone(); } return false; } private void SetupWatcher() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; watcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath)); watcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite; watcher.Changed += OnConfigFileChanged; watcher.EnableRaisingEvents = true; } catch (Exception ex) { Log.LogWarning((object)("Config hot reload unavailable: " + ex.Message)); } } private void OnConfigFileChanged(object sender, FileSystemEventArgs e) { long ticks = DateTime.UtcNow.Ticks; if (ticks >= Interlocked.Read(in ignoreUntilTicks)) { Interlocked.Exchange(ref lastChangeTicks, ticks); reloadPending = true; } } private void Update() { BossKeyWatcher.Check(); if (reloadPending && DateTime.UtcNow.Ticks - Interlocked.Read(in lastChangeTicks) > 5000000) { reloadPending = false; Interlocked.Exchange(ref ignoreUntilTicks, DateTime.UtcNow.Ticks + 20000000); try { ((BaseUnityPlugin)this).Config.Reload(); Log.LogInfo((object)"Config reloaded."); } catch (Exception ex) { Log.LogWarning((object)("Config reload failed: " + ex.Message)); } } } private void OnDestroy() { if (watcher != null) { watcher.EnableRaisingEvents = false; watcher.Dispose(); } } } internal static class ConfigSyncCompat { private static object configSync; [MethodImpl(MethodImplOptions.NoInlining)] internal static void Initialize(string guid, string name, string version) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown configSync = (object)new ConfigSync(guid) { DisplayName = name, CurrentVersion = version, MinimumRequiredVersion = version, ModRequired = false, ModRequirementMode = (ModRequirementMode)1 }; } [MethodImpl(MethodImplOptions.NoInlining)] internal static void AddLockingConfigEntry(ConfigEntry<bool> entry) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) ((ConditionalConfigSync)(ConfigSync)configSync).AddLockingConfigEntry<bool>(entry); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void AddConfigEntry<T>(ConfigEntry<T> entry, bool serverControlled) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) ((ConditionalConfigSync)(ConfigSync)configSync).AddConfigEntry<T>(entry, (ConfigSyncMode)((!serverControlled) ? 2 : 0)); } [MethodImpl(MethodImplOptions.NoInlining)] internal static bool InitialSyncDone() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (configSync != null) { return ((ConditionalConfigSync)(ConfigSync)configSync).InitialSyncDone; } return false; } } internal static class BossKeyWatcher { private const float CheckInterval = 1f; private static readonly HashSet<string> SeenKeys = new HashSet<string>(); private static Player trackedPlayer; private static float nextCheck; public static void Check() { float unscaledTime = Time.unscaledTime; if (unscaledTime < nextCheck) { return; } nextCheck = unscaledTime + 1f; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null) { trackedPlayer = null; return; } if ((Object)(object)localPlayer != (Object)(object)trackedPlayer) { trackedPlayer = localPlayer; SeenKeys.Clear(); { foreach (string key in PlayerThreatLevel.Bosses.Keys) { if (ZoneSystem.instance.GetGlobalKey(key)) { SeenKeys.Add(key); } } return; } } foreach (KeyValuePair<string, BossInfo> boss in PlayerThreatLevel.Bosses) { if (!SeenKeys.Contains(boss.Key) && ZoneSystem.instance.GetGlobalKey(boss.Key)) { SeenKeys.Add(boss.Key); if (!((Character)localPlayer).IsDead()) { Threat.AddBiome(localPlayer, boss.Value); } } } } } internal static class Threat { private const string SaveKey = "ThreatLevel_BiomeMask"; private static readonly int ZdoKey = StringExtensionMethods.GetStableHashCode("ThreatLevel_BiomeMask"); private static int AllBossBits() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected I4, but got Unknown int num = 0; foreach (BossInfo value in PlayerThreatLevel.Bosses.Values) { num |= value.Biome; } return num; } public static int GetMask(Player p) { if ((Object)(object)p == (Object)null) { return 0; } ZNetView component = ((Component)p).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return 0; } return component.GetZDO().GetInt(ZdoKey, 0); } public static void SetMask(Player p, int mask) { ZNetView component = ((Component)p).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner()) { component.GetZDO().Set(ZdoKey, mask, false); p.m_customData["ThreatLevel_BiomeMask"] = mask.ToString(); } } public static int Level(int mask) { mask &= AllBossBits(); int num = 0; while (mask != 0) { num += mask & 1; mask >>= 1; } return num; } public static int Level(Player p) { return Level(GetMask(p)); } public static BossInfo InfoFor(Biome biome) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) foreach (BossInfo value in PlayerThreatLevel.Bosses.Values) { if (value.Biome == biome) { return value; } } return null; } public static string FormatMessage(string template, int level, BossInfo info) { return template.Replace("\\n", "\n").Replace("{level}", level.ToString()).Replace("{max}", PlayerThreatLevel.Bosses.Count.ToString()) .Replace("{biome}", info.BiomeName) .Replace("{boss}", info.BossName); } public static void AddBiome(Player p, BossInfo info, bool announce = true) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected I4, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) int mask = GetMask(p); int num = mask | info.Biome; if (num == mask) { return; } SetMask(p, num); if (announce && PlayerThreatLevel.ShowMessages.Value) { int num2 = Level(num); string value = PlayerThreatLevel.LevelUpMessage.Value; if (num2 >= PlayerThreatLevel.Bosses.Count && !string.IsNullOrEmpty(PlayerThreatLevel.MaxLevelMessage.Value)) { value = PlayerThreatLevel.MaxLevelMessage.Value; } if (!string.IsNullOrEmpty(value)) { ((Character)p).Message(PlayerThreatLevel.MessageLocation.Value, FormatMessage(value, num2, info), 0, (Sprite)null, false); } } } public static void LoadFromSave(Player p) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected I4, but got Unknown int num = GetMask(p); if (p.m_customData.TryGetValue("ThreatLevel_BiomeMask", out var value) && int.TryParse(value, out var result)) { num |= result; } if (PlayerThreatLevel.SeedFromDefeatedBosses && (Object)(object)ZoneSystem.instance != (Object)null) { foreach (KeyValuePair<string, BossInfo> boss in PlayerThreatLevel.Bosses) { if (ZoneSystem.instance.GetGlobalKey(boss.Key)) { num |= boss.Value.Biome; } } } SetMask(p, num); } public static string BiomeList(int mask) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); foreach (BossInfo value in PlayerThreatLevel.Bosses.Values) { if ((mask & value.Biome) != 0) { list.Add(value.BiomeName); } } if (list.Count != 0) { return string.Join(", ", list.ToArray()); } return "none"; } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class PlayerSpawnedPatch { private static void Postfix(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { Threat.LoadFromSave(__instance); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class CreatureRegisterPatch { private static void Postfix(ZNetScene __instance) { PlayerThreatLevel.RegisterCreatures(__instance.m_prefabs); } } [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] internal static class MonsterFearPatch { private class State { public float NextCheck; public float AfraidUntil; public Player ScaredOf; public Character Char; public ZNetView NView; public string PrefabName; } private static readonly int ProvokedByKey = StringExtensionMethods.GetStableHashCode("ThreatLevel_ProvokedBy"); private static readonly int ProvokedUntilKey = StringExtensionMethods.GetStableHashCode("ThreatLevel_ProvokedUntil"); private static readonly int FearlessUntilKey = StringExtensionMethods.GetStableHashCode("ThreatLevel_FearlessUntil"); private static readonly ConditionalWeakTable<MonsterAI, State> States = new ConditionalWeakTable<MonsterAI, State>(); private static readonly Func<BaseAI, float, Vector3, bool> Flee = MakeFlee(); private static readonly Action<BaseAI, bool> SetAlerted = MakeSetAlerted(); private static long NowTicks() { if (!((Object)(object)ZNet.instance != (Object)null)) { return DateTime.UtcNow.Ticks; } return ZNet.instance.GetTime().Ticks; } private static long SecondsToTicks(float seconds) { return (long)(seconds * 10000000f); } internal static void OnAttacked(MonsterAI ai, Player attacker) { ZNetView component = ((Component)ai).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return; } ZDO zDO = component.GetZDO(); long num = NowTicks(); bool flag = false; if (PlayerThreatLevel.HostileIfAttacked) { float hostileDuration = PlayerThreatLevel.HostileDuration; zDO.Set(ProvokedByKey, attacker.GetPlayerID()); zDO.Set(ProvokedUntilKey, (hostileDuration <= 0f) ? long.MaxValue : (num + SecondsToTicks(hostileDuration))); flag = true; } float fearImmunityAfterAttack = PlayerThreatLevel.FearImmunityAfterAttack; if (fearImmunityAfterAttack > 0f) { long num2 = num + SecondsToTicks(fearImmunityAfterAttack); if (num2 > zDO.GetLong(FearlessUntilKey, 0L)) { zDO.Set(FearlessUntilKey, num2); } flag = true; } if (flag) { State orCreateValue = States.GetOrCreateValue(ai); orCreateValue.AfraidUntil = 0f; orCreateValue.ScaredOf = null; orCreateValue.NextCheck = 0f; } } private static Func<BaseAI, float, Vector3, bool> MakeFlee() { try { MethodInfo method = typeof(BaseAI).GetMethod("Flee", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(float), typeof(Vector3) }, null); return (Func<BaseAI, float, Vector3, bool>)Delegate.CreateDelegate(typeof(Func<BaseAI, float, Vector3, bool>), method); } catch (Exception ex) { PlayerThreatLevel.Log.LogError((object)("Could not bind BaseAI.Flee - fear disabled: " + ex.Message)); return null; } } private static Action<BaseAI, bool> MakeSetAlerted() { try { MethodInfo method = typeof(BaseAI).GetMethod("SetAlerted", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(bool) }, null); return (Action<BaseAI, bool>)Delegate.CreateDelegate(typeof(Action<BaseAI, bool>), method); } catch (Exception ex) { PlayerThreatLevel.Log.LogWarning((object)("Could not bind BaseAI.SetAlerted - no exclamation mark on fleeing monsters: " + ex.Message)); return null; } } private static bool HasAlliesNearby(Character self, float radius) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (radius <= 0f) { return false; } Vector3 position = ((Component)self).transform.position; float num = radius * radius; Faction faction = self.GetFaction(); foreach (Character allCharacter in Character.GetAllCharacters()) { if (!((Object)(object)allCharacter == (Object)null) && !((Object)(object)allCharacter == (Object)(object)self) && !(allCharacter is Player) && !allCharacter.IsDead() && allCharacter.GetFaction() == faction) { Vector3 val = ((Component)allCharacter).transform.position - position; if (!(((Vector3)(ref val)).sqrMagnitude > num)) { return true; } } } return false; } private static Player FindScaryPlayer(Vector3 pos, long ignoredPlayerId) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) Biome val = (Biome)0; bool flag = false; Player result = null; float num = float.MaxValue; foreach (Player allPlayer in Player.GetAllPlayers()) { if ((Object)(object)allPlayer == (Object)null || ((Character)allPlayer).IsDead() || (ignoredPlayerId != 0L && allPlayer.GetPlayerID() == ignoredPlayerId)) { continue; } int mask = Threat.GetMask(allPlayer); int num2 = Threat.Level(mask); if (num2 <= 0) { continue; } float num3 = PlayerThreatLevel.BaseFearRadius + PlayerThreatLevel.FearRadiusPerLevel * (float)(num2 - 1); float num4 = Vector3.Distance(pos, ((Component)allPlayer).transform.position); if (!(num4 > num3) && !(num4 >= num)) { if (!flag) { val = Heightmap.FindBiome(pos); flag = true; } if ((mask & val) != 0) { result = allPlayer; num = num4; } } } return result; } private static bool Prefix(MonsterAI __instance, float dt, ref bool __result) { //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) if (Flee == null) { return true; } State orCreateValue = States.GetOrCreateValue(__instance); if ((Object)(object)orCreateValue.Char == (Object)null) { orCreateValue.Char = ((Component)__instance).GetComponent<Character>(); orCreateValue.NView = ((Component)__instance).GetComponent<ZNetView>(); orCreateValue.PrefabName = Utils.GetPrefabName(((Component)__instance).gameObject); } if ((Object)(object)orCreateValue.Char == (Object)null || (Object)(object)orCreateValue.NView == (Object)null || !orCreateValue.NView.IsValid() || !orCreateValue.NView.IsOwner()) { return true; } if (orCreateValue.Char.IsDead() || orCreateValue.Char.IsTamed()) { return true; } if (PlayerThreatLevel.BossesImmune && orCreateValue.Char.IsBoss()) { return true; } if (PlayerThreatLevel.StarredImmune && orCreateValue.Char.GetLevel() >= 2) { return true; } if (!PlayerThreatLevel.IsCreatureEnabled(orCreateValue.PrefabName)) { return true; } float time = Time.time; if (time >= orCreateValue.NextCheck) { orCreateValue.NextCheck = time + 0.25f; ZDO zDO = orCreateValue.NView.GetZDO(); long num = NowTicks(); if (zDO.GetLong(FearlessUntilKey, 0L) > num) { orCreateValue.AfraidUntil = 0f; orCreateValue.ScaredOf = null; } else { long ignoredPlayerId = ((zDO.GetLong(ProvokedUntilKey, 0L) > num) ? zDO.GetLong(ProvokedByKey, 0L) : 0); bool flag = time < orCreateValue.AfraidUntil; Player val = FindScaryPlayer(((Component)orCreateValue.Char).transform.position, ignoredPlayerId); if ((Object)(object)val != (Object)null || flag) { if (HasAlliesNearby(orCreateValue.Char, PlayerThreatLevel.AllyCourageRadius)) { orCreateValue.AfraidUntil = 0f; orCreateValue.ScaredOf = null; } else if ((Object)(object)val != (Object)null) { orCreateValue.ScaredOf = val; orCreateValue.AfraidUntil = time + PlayerThreatLevel.FearDuration; } } } } if (time < orCreateValue.AfraidUntil && (Object)(object)orCreateValue.ScaredOf != (Object)null) { if (SetAlerted != null && PlayerThreatLevel.AlertWhenFleeing) { SetAlerted((BaseAI)(object)__instance, arg2: true); } Flee((BaseAI)(object)__instance, dt, ((Component)orCreateValue.ScaredOf).transform.position); __result = true; return false; } return true; } } [HarmonyPatch(typeof(MonsterAI), "OnDamaged")] internal static class MonsterDamagedPatch { private static void Postfix(MonsterAI __instance, Character attacker) { Player val = (Player)(object)((attacker is Player) ? attacker : null); if (!((Object)(object)val == (Object)null)) { MonsterFearPatch.OnAttacked(__instance, val); } } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class ThreatCommandPatch { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; internal void <Postfix>b__0_0(ConsoleEventArgs args) { //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { args.Context.AddString("No local player."); return; } if (args.Length >= 2) { switch (args[1].ToLowerInvariant()) { case "reset": Threat.SetMask(localPlayer, 0); break; case "creatures": { string text = string.Join(", ", new List<string>(PlayerThreatLevel.DisabledCreatures()).ToArray()); args.Context.AddString("Creatures that ignore threat: " + ((text.Length == 0) ? "none" : text)); return; } case "all": foreach (BossInfo value in PlayerThreatLevel.Bosses.Values) { Threat.AddBiome(localPlayer, value, announce: false); } break; case "add": if (args.Length >= 3) { Biome biome; try { biome = (Biome)Enum.Parse(typeof(Biome), args[2], ignoreCase: true); } catch { args.Context.AddString("Unknown biome: " + args[2]); return; } BossInfo bossInfo = Threat.InfoFor(biome); if (bossInfo == null) { args.Context.AddString("No boss is tied to " + args[2]); } else { Threat.AddBiome(localPlayer, bossInfo); } } break; } } int mask = Threat.GetMask(localPlayer); string text2 = (PlayerThreatLevel.IsSyncedFromServer() ? " (settings synced from server)" : ""); args.Context.AddString("Threat level " + Threat.Level(mask) + "/" + PlayerThreatLevel.Bosses.Count + " - feared in: " + Threat.BiomeList(mask) + text2); } } private static void Postfix() { //IL_0033: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { args.Context.AddString("No local player."); } else { if (args.Length >= 2) { switch (args[1].ToLowerInvariant()) { case "reset": Threat.SetMask(localPlayer, 0); break; case "creatures": { string text = string.Join(", ", new List<string>(PlayerThreatLevel.DisabledCreatures()).ToArray()); args.Context.AddString("Creatures that ignore threat: " + ((text.Length == 0) ? "none" : text)); return; } case "all": foreach (BossInfo value in PlayerThreatLevel.Bosses.Values) { Threat.AddBiome(localPlayer, value, announce: false); } break; case "add": if (args.Length >= 3) { Biome biome; try { biome = (Biome)Enum.Parse(typeof(Biome), args[2], ignoreCase: true); } catch { args.Context.AddString("Unknown biome: " + args[2]); return; } BossInfo bossInfo = Threat.InfoFor(biome); if (bossInfo == null) { args.Context.AddString("No boss is tied to " + args[2]); } else { Threat.AddBiome(localPlayer, bossInfo); } } break; } } int mask = Threat.GetMask(localPlayer); string text2 = (PlayerThreatLevel.IsSyncedFromServer() ? " (settings synced from server)" : ""); args.Context.AddString("Threat level " + Threat.Level(mask) + "/" + PlayerThreatLevel.Bosses.Count + " - feared in: " + Threat.BiomeList(mask) + text2); } }; <>c.<>9__0_0 = val; obj = (object)val; } new ConsoleCommand("threat", "threat [reset | all | add <biome> | creatures] - view or edit your threat level", (ConsoleEvent)obj, true, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } } }