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 MobFriendlyFire v1.2.4
MobFriendlyFire.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("MobFriendlyFire")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MobFriendlyFire")] [assembly: AssemblyTitle("MobFriendlyFire")] [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 MobFriendlyFire { [BepInPlugin("hergey.MobFriendlyFire", "MobFriendlyFire", "1.2.4")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "hergey.MobFriendlyFire"; public const string Version = "1.2.4"; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> DamageMultiplier; internal static ConfigEntry<float> HitChance; internal static ConfigEntry<bool> Projectiles; internal static ConfigEntry<bool> Explosions; internal static ConfigEntry<bool> ExemptBosses; internal static ConfigEntry<string> Excluded; internal static ConfigEntry<float> GrudgeChance; internal static ConfigEntry<float> GrudgeSeconds; private static HashSet<string> excludedNames = new HashSet<string>(); private void Awake() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Expected O, but got Unknown //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Expected O, but got Unknown //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Expected O, but got Unknown //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Expected O, but got Unknown //IL_023c: Unknown result type (might be due to invalid IL or missing references) ConfigurationManagerAttributes val = new ConfigurationManagerAttributes { IsAdminOnly = true }; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, new ConfigDescription("Les coups des monstres sauvages blessent aussi leurs alliés (sans changer leurs cibles).", (AcceptableValueBase)null, new object[1] { val })); DamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1 - General", "Damage multiplier", 0.6f, new ConfigDescription("Part des dégâts infligés à un allié (1 = 100 %, 0.5 = moitié).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), new object[1] { val })); HitChance = ((BaseUnityPlugin)this).Config.Bind<float>("1 - General", "Hit chance", 1f, new ConfigDescription("Chance qu'un coup qui touche un allié le blesse vraiment (1 = toujours, 0.5 = une fois sur deux).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { val })); Projectiles = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Projectiles", true, new ConfigDescription("Flèches, pierres et autres projectiles de monstres touchent aussi leurs alliés.", (AcceptableValueBase)null, new object[1] { val })); Explosions = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Explosions", true, new ConfigDescription("Explosions et zones (poison, feu...) touchent aussi les monstres du même type que leur auteur.", (AcceptableValueBase)null, new object[1] { val })); ExemptBosses = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Exempt bosses", true, new ConfigDescription("Les boss ne blessent pas leurs alliés et ne prennent pas de dégâts de leurs alliés.", (AcceptableValueBase)null, new object[1] { val })); Excluded = ((BaseUnityPlugin)this).Config.Bind<string>("1 - General", "Excluded creatures", "", new ConfigDescription("Noms de prefab exclus, séparés par des virgules (ex : Greydwarf_Shaman, Troll). Un monstre exclu ne blesse pas ses alliés et n'est pas blessé par eux.", (AcceptableValueBase)null, new object[1] { val })); GrudgeChance = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Grudge", "Chance", 0.2f, new ConfigDescription("Chance qu'un monstre blessé par un allié se retourne contre lui (0 = jamais, 1 = toujours).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { val })); GrudgeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("2 - Grudge", "Duration seconds", 8f, new ConfigDescription("Durée pendant laquelle le monstre rancunier traite l'allié qui l'a blessé comme un ennemi.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), new object[1] { val })); ParseExcluded(); Excluded.SettingChanged += delegate { ParseExcluded(); }; new Harmony("hergey.MobFriendlyFire").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)(string.Format("MobFriendlyFire {0} chargé : actif={1}, dégâts={2:0.##}, chance={3:0.##}, ", "1.2.4", Enabled.Value, DamageMultiplier.Value, HitChance.Value) + $"projectiles={Projectiles.Value}, explosions={Explosions.Value}, boss exemptés={ExemptBosses.Value}, " + string.Format("rancune={0:0.##} ({1:0.#} s), exclus=[{2}]", GrudgeChance.Value, GrudgeSeconds.Value, string.Join(", ", excludedNames)))); } private static void ParseExcluded() { excludedNames = new HashSet<string>(from s in Excluded.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries) select s.Trim() into s where s.Length > 0 select s, StringComparer.OrdinalIgnoreCase); } internal static bool IsExcluded(Character c) { if (excludedNames.Count > 0) { return excludedNames.Contains(Utils.GetPrefabName(((Component)c).gameObject)); } return false; } internal static bool IsWildMob(Character c) { if (Enabled.Value && (Object)(object)c != (Object)null && !c.IsPlayer() && !c.IsTamed() && (!ExemptBosses.Value || !c.IsBoss())) { return !IsExcluded(c); } return false; } } [HarmonyPatch(typeof(Attack))] internal static class AttackPatch { private static readonly FieldRef<Attack, Humanoid> AttackerRef = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character"); [HarmonyPrefix] [HarmonyPatch("DoMeleeAttack")] private static void MeleePrefix(Attack __instance) { Apply(__instance); } [HarmonyPrefix] [HarmonyPatch("DoAreaAttack")] private static void AreaPrefix(Attack __instance) { Apply(__instance); } private static void Apply(Attack attack) { if (Plugin.IsWildMob((Character)(object)AttackerRef.Invoke(attack))) { attack.m_hitFriendly = true; } } } [HarmonyPatch(typeof(Projectile), "Setup")] internal static class ProjectilePatch { private static void Postfix(Projectile __instance, Character owner) { if (Plugin.Projectiles.Value && Plugin.IsWildMob(owner)) { __instance.m_hitFriendly = true; __instance.m_noDamageFriendly = false; } } } [HarmonyPatch(typeof(Aoe), "Setup")] internal static class AoePatch { private static void Postfix(Aoe __instance, Character owner) { if (Plugin.Explosions.Value && Plugin.IsWildMob(owner)) { __instance.m_hitFriendly = true; __instance.m_hitSame = true; } } } [HarmonyPatch(typeof(Character), "Damage")] internal static class DamagePatch { private static bool Prefix(Character __instance, HitData hit) { if (!Plugin.Enabled.Value || hit == null || __instance.IsPlayer()) { return true; } Character attacker = hit.GetAttacker(); if ((Object)(object)attacker == (Object)null || (Object)(object)attacker == (Object)(object)__instance || attacker.IsPlayer() || attacker.IsTamed() || BaseAI.IsEnemy(attacker, __instance)) { return true; } if ((Plugin.ExemptBosses.Value && __instance.IsBoss()) || Plugin.IsExcluded(__instance)) { return false; } if (Random.value >= Plugin.HitChance.Value) { return false; } if (Plugin.DamageMultiplier.Value != 1f) { hit.ApplyModifier(Plugin.DamageMultiplier.Value); } return true; } } internal static class Grudges { private static readonly Dictionary<(int victim, int attacker), float> until = new Dictionary<(int, int), float>(); internal static void Add(Character victim, Character attacker) { until[(((Object)victim).GetInstanceID(), ((Object)attacker).GetInstanceID())] = Time.time + Plugin.GrudgeSeconds.Value; } internal static bool Has(Character a, Character b) { if (until.Count == 0 || (Object)(object)a == (Object)null || (Object)(object)b == (Object)null) { return false; } (int, int) key = (((Object)a).GetInstanceID(), ((Object)b).GetInstanceID()); if (!until.TryGetValue(key, out var value)) { return false; } if (Time.time <= value) { return true; } until.Remove(key); return false; } } [HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[] { typeof(Character), typeof(Character) })] internal static class IsEnemyPatch { private static void Postfix(Character a, Character b, ref bool __result) { if (!__result && Grudges.Has(a, b)) { __result = true; } } } [HarmonyPatch(typeof(MonsterAI), "OnDamaged")] internal static class GrudgePatch { private static readonly FieldRef<MonsterAI, Character> TargetRef = AccessTools.FieldRefAccess<MonsterAI, Character>("m_targetCreature"); private static void Postfix(MonsterAI __instance, Character attacker) { if (!(Plugin.GrudgeChance.Value <= 0f) && !((Object)(object)attacker == (Object)null)) { Character component = ((Component)__instance).GetComponent<Character>(); if (Plugin.IsWildMob(component) && Plugin.IsWildMob(attacker) && !BaseAI.IsEnemy(component, attacker) && !(Random.value >= Plugin.GrudgeChance.Value)) { Grudges.Add(component, attacker); TargetRef.Invoke(__instance) = attacker; } } } } }