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 BossAffixByPlayers v1.0.4
BepInEx\plugins\Cjayride.BossGroupAffix.dll
Decompiled 2 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: AssemblyCompany("Cjayride.BossGroupAffix")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.4.0")] [assembly: AssemblyInformationalVersion("1.0.4+eb1be48ca009e441df618dd16f77a31de42125b9")] [assembly: AssemblyProduct("Cjayride.BossGroupAffix")] [assembly: AssemblyTitle("Cjayride.BossGroupAffix")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.4.0")] [module: UnverifiableCode] [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 Cjayride.BossGroupAffix { [HarmonyPatch(typeof(Character), "Awake")] internal static class Character_Awake_Patch { private static void Postfix(Character __instance) { if (Object.op_Implicit((Object)(object)__instance) && __instance.IsBoss()) { ConfigEntry<bool> swapAffixByPlayerCount = Plugin.SwapAffixByPlayerCount; if (swapAffixByPlayerCount != null && swapAffixByPlayerCount.Value && Cllc.Ready && !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<AffixWatcher>())) { ((Component)__instance).gameObject.AddComponent<AffixWatcher>(); } } } } internal sealed class AffixWatcher : MonoBehaviour { private const string ZdoLocked = "cjayride.BossGroupAffix.Locked"; private const float Interval = 2f; private Character _boss; private float _timer; private void Awake() { _boss = ((Component)this).GetComponent<Character>(); } private void Update() { _timer += Time.deltaTime; if (!(_timer < 2f)) { _timer = 0f; Check(); } } private void Check() { if (Plugin.SwapAffixByPlayerCount.Value && Cllc.Ready && Plugin.Enabled.Value && Object.op_Implicit((Object)(object)_boss) && !_boss.IsDead() && Object.op_Implicit((Object)(object)_boss.m_nview) && _boss.m_nview.IsValid() && _boss.m_nview.IsOwner()) { ZDO zDO = _boss.m_nview.GetZDO(); if (zDO.GetBool("cjayride.BossGroupAffix.Locked", false)) { ((Behaviour)this).enabled = false; } else if (_boss.GetHealth() < _boss.GetMaxHealth()) { ApplyAffixForPlayerCount(); zDO.Set("cjayride.BossGroupAffix.Locked", true); ((Behaviour)this).enabled = false; } else { ApplyAffixForPlayerCount(); } } } private void ApplyAffixForPlayerCount() { string text = Cllc.Get(_boss); if (!(text == "Twin") && !(text == "Godlike")) { int num = BossNearbyPlayers.CountLivingNear(_boss); string text2 = ((num <= 1) ? Plugin.SoloAffix.Value : Plugin.GroupAffix.Value); if (Cllc.IsValid(text2) && !(text2 == text)) { Cllc.Set(_boss, text2); Plugin.Log.LogInfo((object)$"Boss Affix By Players: {_boss.m_name} affix {text} -> {text2} ({num} player(s) in range)."); } } } } internal static class BossNearbyPlayers { private static readonly List<Player> Buffer = new List<Player>(); internal static int CountLivingNear(Character boss) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)boss)) { return 0; } return CountLivingNear(((Component)boss).transform.position); } internal static int CountLivingNear(Vector3 position) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) float num = Plugin.PlayerRange?.Value ?? 0f; if (num <= 0f) { return 0; } Buffer.Clear(); Player.GetPlayersInRange(position, num, Buffer); int num2 = 0; for (int i = 0; i < Buffer.Count; i++) { Player val = Buffer[i]; if (Object.op_Implicit((Object)(object)val) && !((Character)val).IsDead()) { num2++; } } Buffer.Clear(); return num2; } } [HarmonyPatch(typeof(OfferingBowl), "InitiateSpawnBoss")] internal static class BossSummonGate_Initiate { private static readonly FieldInfo InteractUser = AccessTools.Field(typeof(OfferingBowl), "m_interactUser"); private static bool Prefix(OfferingBowl __instance, Vector3 point, bool removeItemsFromInventory) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) ConfigEntry<bool> enabled = Plugin.Enabled; if (enabled == null || !enabled.Value) { return true; } int num = Plugin.MinPlayersToStartFight?.Value ?? 0; if (num <= 0 || (Object)(object)__instance == (Object)null || (Object)(object)__instance.m_bossPrefab == (Object)null) { return true; } int num2 = BossNearbyPlayers.CountLivingNear(point); if (num2 >= num) { return true; } object? obj = InteractUser?.GetValue(__instance); BossSummonMessages.Show((Humanoid)((obj is Humanoid) ? obj : null), num, num2); return false; } } [HarmonyPatch(typeof(OfferingBowl), "RPC_SpawnBoss")] internal static class BossSummonGate_Rpc { private static bool Prefix(OfferingBowl __instance, Vector3 point, bool removeItemsFromInventory) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) ConfigEntry<bool> enabled = Plugin.Enabled; if (enabled == null || !enabled.Value) { return true; } int num = Plugin.MinPlayersToStartFight?.Value ?? 0; if (num <= 0 || (Object)(object)__instance == (Object)null || (Object)(object)__instance.m_bossPrefab == (Object)null) { return true; } if (BossNearbyPlayers.CountLivingNear(point) >= num) { return true; } return false; } } internal static class BossSummonMessages { private static float _lastMessageTime; internal static void Show(Humanoid user, int required, int present) { if (!((Object)(object)user == (Object)null) && !((Object)(object)user != (Object)(object)Player.m_localPlayer)) { float num = Plugin.MessageCooldownSeconds?.Value ?? 3f; if (!(Time.time - _lastMessageTime < num)) { _lastMessageTime = Time.time; string text = string.Format(Plugin.FightBlockedMessage?.Value ?? "Need at least {0} players within {1}m of the boss spawn to summon ({2} nearby).", required, Mathf.RoundToInt(Plugin.PlayerRange?.Value ?? 0f), present); ((Character)user).Message((MessageType)2, text, 0, (Sprite)null, false); } } } } [BepInPlugin("cjayride.bossgroupaffix", "Boss Affix By Players", "1.0.4")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "cjayride.bossgroupaffix"; public const string PluginName = "Boss Affix By Players"; public const string PluginVersion = "1.0.4"; internal const string CllcGuid = "org.bepinex.plugins.creaturelevelcontrol"; internal static Plugin Instance; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> SwapAffixByPlayerCount; internal static ConfigEntry<string> SoloAffix; internal static ConfigEntry<string> GroupAffix; internal static ConfigEntry<float> PlayerRange; internal static ConfigEntry<int> MinPlayersToStartFight; internal static ConfigEntry<string> FightBlockedMessage; internal static ConfigEntry<float> MessageCooldownSeconds; internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger; private void Awake() { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Expected O, but got Unknown //IL_0189: Unknown result type (might be due to invalid IL or missing references) Instance = this; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "When true, MinPlayersToStartFight and optional affix swapping are active."); SwapAffixByPlayerCount = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SwapAffixByPlayerCount", false, "When true, CL&LC boss affix is chosen from nearby player count (solo vs group). When false, affix swapping is off."); SoloAffix = ((BaseUnityPlugin)this).Config.Bind<string>("Affix swap", "SoloAffix", "Reflective", "Used only when SwapAffixByPlayerCount is true and one living player is in range. One of: None, Reflective, Shielded, Mending, Summoner, Elementalist, Enraged, Sturdy."); GroupAffix = ((BaseUnityPlugin)this).Config.Bind<string>("Affix swap", "GroupAffix", "Summoner", "Used only when SwapAffixByPlayerCount is true and two or more living players are in range."); PlayerRange = ((BaseUnityPlugin)this).Config.Bind<float>("General", "PlayerRange", 180f, "Meters from the boss. Living players inside this radius count toward starting the fight and toward affix swap."); MinPlayersToStartFight = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MinPlayersToStartFight", 2, new ConfigDescription("Offering a boss summon requires at least this many living players within PlayerRange of the spawn point. 0 disables the check.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10), Array.Empty<object>())); FightBlockedMessage = ((BaseUnityPlugin)this).Config.Bind<string>("General", "FightBlockedMessage", "Need at least {0} players within {1}m of the boss spawn to summon ({2} nearby).", "HUD text when a summon is blocked. {0} = required count, {1} = PlayerRange, {2} = current count."); MessageCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MessageCooldownSeconds", 3f, new ConfigDescription("Minimum seconds between fight-blocked messages for the local player.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 30f), Array.Empty<object>())); WarnIfAffixInvalid(SoloAffix); WarnIfAffixInvalid(GroupAffix); ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Boss Affix By Players 1.0.4 loaded. Config: " + ((BaseUnityPlugin)this).Config.ConfigFilePath)); new Harmony("cjayride.bossgroupaffix").PatchAll(Assembly.GetExecutingAssembly()); if (!Cllc.Init()) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Creature Level & Loot Control API not found; affix swapping is disabled until CL&LC is installed."); } } private static void WarnIfAffixInvalid(ConfigEntry<string> entry) { if (entry != null && !Cllc.IsValid(entry.Value)) { Log.LogWarning((object)("Config " + ((ConfigEntryBase)entry).Definition.Section + "/" + ((ConfigEntryBase)entry).Definition.Key + " = \"" + entry.Value + "\" is not a valid CL&LC boss affix.")); } } } internal static class Cllc { private static Type _affixType; private static MethodInfo _get; private static MethodInfo _set; internal static bool Ready { get { if (_get != null) { return _set != null; } return false; } } internal static bool Init() { Type type = AccessTools.TypeByName("CreatureLevelControl.API"); _affixType = AccessTools.TypeByName("CreatureLevelControl.BossAffix"); if (type == null || _affixType == null) { return false; } _get = AccessTools.Method(type, "GetAffixBoss", new Type[1] { typeof(Character) }, (Type[])null); _set = AccessTools.Method(type, "SetAffixBoss", new Type[2] { typeof(Character), _affixType }, (Type[])null); if (_get != null) { return _set != null; } return false; } internal static string Get(Character boss) { return _get.Invoke(null, new object[1] { boss })?.ToString() ?? "None"; } internal static void Set(Character boss, string affix) { _set.Invoke(null, new object[2] { boss, Enum.Parse(_affixType, affix) }); } internal static bool IsValid(string affix) { if (_affixType == null) { if (!string.IsNullOrEmpty(affix) && affix != "Twin") { return affix != "Godlike"; } return false; } if (string.IsNullOrEmpty(affix) || affix == "Twin" || affix == "Godlike") { return false; } try { Enum.Parse(_affixType, affix); return true; } catch (ArgumentException) { return false; } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }