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 SmartShield v1.0.11
plugins\cjayride-SmartShield\Cjayride.SmartShield.dll
Decompiled 3 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.SmartShield")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.11.0")] [assembly: AssemblyInformationalVersion("1.0.11+ca95b60e6d1e8c9e43abf5b918a43edd8c88eb57")] [assembly: AssemblyProduct("Cjayride.SmartShield")] [assembly: AssemblyTitle("Cjayride.SmartShield")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.11.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.SmartShield { internal static class ModConfig { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> AutoEquipOnOneHanded; internal static ConfigEntry<bool> EquipAfterRanged; internal static ConfigEntry<bool> UnequipOnTwoHanded; internal static ConfigEntry<bool> UnequipOnSheath; internal static ConfigEntry<bool> UnequipOnHotbarDeselect; internal static ConfigEntry<string> SelectionMode; internal static ConfigEntry<string> PreferredShield; internal static ConfigEntry<string> AllowedWeaponTypes; internal static ConfigEntry<string> BlacklistShields; internal static void Bind(ConfigFile config) { Enabled = config.Bind<bool>("General", "Enabled", true, "Master switch. No messages are ever shown."); AutoEquipOnOneHanded = config.Bind<bool>("Behavior", "AutoEquipOnOneHanded", true, "Equip a shield whenever a one-handed weapon is equipped."); EquipAfterRanged = config.Bind<bool>("Behavior", "EquipAfterRanged", true, "Also equip a shield after switching from a bow/crossbow (or other ranged) to a one-handed weapon."); UnequipOnTwoHanded = config.Bind<bool>("Behavior", "UnequipOnTwoHanded", true, "Unequip the shield when a two-handed or ranged weapon is equipped."); UnequipOnSheath = config.Bind<bool>("Behavior", "UnequipOnSheath", false, "When true, stow the shield in inventory on R-sheath (weapon-only on your back). When false, vanilla dual back display (weapon + shield)."); UnequipOnHotbarDeselect = config.Bind<bool>("Behavior", "UnequipOnHotbarDeselect", true, "Unequip the shield when you deselect a one-handed weapon on the hotbar (press the same slot again). Does not unequip if you manually equip a shield alone."); SelectionMode = config.Bind<string>("ShieldSelection", "SelectionMode", "Best", "Best = highest block power. First = first shield in inventory. Preferred = use PreferredShield."); PreferredShield = config.Bind<string>("ShieldSelection", "PreferredShield", "", "Prefab name used when SelectionMode is Preferred (example: ShieldWood)."); AllowedWeaponTypes = config.Bind<string>("Filters", "AllowedWeaponTypes", "", "Comma-separated ItemType, skill, or prefab names. Empty = all one-handed weapons."); BlacklistShields = config.Bind<string>("Filters", "BlacklistShields", "", "Comma-separated shield prefab names that must never be auto-equipped."); } } [BepInPlugin("cjayride.smartshield", "SmartShield", "1.0.11")] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "cjayride.smartshield"; public const string PluginName = "SmartShield"; public const string PluginVersion = "1.0.11"; internal static Plugin Instance; internal static Harmony Harmony; private float _seenPlayerAt = -1f; private float _nextPoll; private bool _baselined; private int _catchUpPolls; internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger; private void Awake() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown Instance = this; ModConfig.Bind(((BaseUnityPlugin)this).Config); Harmony = new Harmony("cjayride.smartshield"); Harmony.PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SmartShield 1.0.11 loaded."); } private void Update() { if (!ModConfig.Enabled.Value) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead()) { _seenPlayerAt = -1f; _baselined = false; _catchUpPolls = 0; } else if (_seenPlayerAt < 0f) { _seenPlayerAt = Time.unscaledTime; } else { if (Time.unscaledTime < _seenPlayerAt + 1.5f || Time.unscaledTime < _nextPoll) { return; } _nextPoll = Time.unscaledTime + 0.12f; if (!_baselined) { ShieldService.Baseline(localPlayer); _baselined = true; ShieldService.Apply(); _catchUpPolls = 10; return; } ShieldService.Tick(localPlayer); if (_catchUpPolls > 0) { _catchUpPolls--; ShieldService.Apply(); } } } } [HarmonyPatch(typeof(Humanoid), "HideHandItems")] internal static class PatchHideHandItems { private static void Postfix(Humanoid __instance, bool onlyRightHand) { if (!onlyRightHand && IsLocal(__instance) && SheathUnequipEnabled()) { ShieldService.RetractShieldWhileSheathed(__instance); } } private static bool IsLocal(Humanoid humanoid) { if ((Object)(object)humanoid != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null) { return (Object)(object)humanoid == (Object)(object)Player.m_localPlayer; } return false; } private static bool SheathUnequipEnabled() { if (ModConfig.Enabled != null && ModConfig.Enabled.Value && ModConfig.UnequipOnSheath != null) { return ModConfig.UnequipOnSheath.Value; } return false; } } [HarmonyPatch(typeof(Humanoid), "ShowHandItems")] internal static class PatchShowHandItems { private static void Prefix(Humanoid __instance, bool onlyRightHand) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 if (!onlyRightHand && IsLocal(__instance) && SheathUnequipEnabled()) { ItemData hiddenLeftItem = __instance.m_hiddenLeftItem; if (hiddenLeftItem?.m_shared != null && (int)hiddenLeftItem.m_shared.m_itemType == 5) { __instance.m_hiddenLeftItem = null; } } } private static void Postfix(Humanoid __instance, bool onlyRightHand) { if (!onlyRightHand && IsLocal(__instance) && ModConfig.Enabled != null && ModConfig.Enabled.Value) { ShieldService.NotifyHandsShown(); ShieldService.Apply(); } } private static bool IsLocal(Humanoid humanoid) { if ((Object)(object)humanoid != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null) { return (Object)(object)humanoid == (Object)(object)Player.m_localPlayer; } return false; } private static bool SheathUnequipEnabled() { if (ModConfig.Enabled != null && ModConfig.Enabled.Value && ModConfig.UnequipOnSheath != null) { return ModConfig.UnequipOnSheath.Value; } return false; } } internal static class ShieldService { internal static bool InternalChange; private static bool _previousWasRangedOrTwoHanded; private static ItemData _lastRight; private static bool _wasSheathed; private static float _ignoreHotbarUnequipUntil; internal static void Baseline(Player player) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) ItemData val = (_lastRight = ((Humanoid)player).GetRightItem()); _wasSheathed = IsSheathed((Humanoid)(object)player); _previousWasRangedOrTwoHanded = val?.m_shared != null && IsRangedOrTwoHanded(val.m_shared.m_itemType); } internal static void NotifyHandsShown() { _ignoreHotbarUnequipUntil = Time.unscaledTime + 0.35f; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { _lastRight = ((Humanoid)localPlayer).GetRightItem(); _wasSheathed = IsSheathed((Humanoid)(object)localPlayer); } } internal static void Tick(Player player) { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Invalid comparison between Unknown and I4 ItemData lastRight = _lastRight; ItemData rightItem = ((Humanoid)player).GetRightItem(); ItemData leftItem = ((Humanoid)player).GetLeftItem(); bool flag = IsSheathed((Humanoid)(object)player); if (ModConfig.UnequipOnSheath.Value && flag && ShieldStillAttachedWhileSheathed((Humanoid)(object)player)) { _lastRight = rightItem; _wasSheathed = true; Apply(); return; } bool num = rightItem != lastRight; bool flag2 = flag != _wasSheathed; if (!num && !flag2) { return; } if (ModConfig.UnequipOnHotbarDeselect.Value && Time.unscaledTime >= _ignoreHotbarUnequipUntil && rightItem == null && !flag && lastRight != null && IsOneHandedWeapon(lastRight) && leftItem?.m_shared != null && (int)leftItem.m_shared.m_itemType == 5) { _lastRight = rightItem; _wasSheathed = flag; UnequipSilent((Humanoid)(object)player, leftItem); return; } if (rightItem?.m_shared != null && IsRangedOrTwoHanded(rightItem.m_shared.m_itemType)) { _previousWasRangedOrTwoHanded = true; } _lastRight = rightItem; _wasSheathed = flag; Apply(); } internal static void Apply() { if (!ModConfig.Enabled.Value || InternalChange) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead()) { return; } try { ApplyInner(localPlayer); } catch (Exception ex) { Plugin.Log.LogWarning((object)("SmartShield apply failed: " + ex.Message)); } } private static void ApplyInner(Player player) { //IL_0028: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Invalid comparison between Unknown and I4 //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Invalid comparison between Unknown and I4 //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Invalid comparison between Unknown and I4 ItemData rightItem = ((Humanoid)player).GetRightItem(); ItemData leftItem = ((Humanoid)player).GetLeftItem(); bool previousWasRangedOrTwoHanded = _previousWasRangedOrTwoHanded; _previousWasRangedOrTwoHanded = rightItem?.m_shared != null && IsRangedOrTwoHanded(rightItem.m_shared.m_itemType); if (IsSheathed((Humanoid)(object)player)) { if (ModConfig.UnequipOnSheath.Value) { RetractShieldWhileSheathed((Humanoid)(object)player); } } else { if (rightItem == null) { return; } if (IsRangedOrTwoHanded(rightItem.m_shared.m_itemType)) { if (ModConfig.UnequipOnTwoHanded.Value && leftItem != null && (int)leftItem.m_shared.m_itemType == 5) { UnequipSilent((Humanoid)(object)player, leftItem); } } else { if (rightItem == null || !IsOneHandedWeapon(rightItem) || !WeaponAllowed(rightItem)) { return; } bool flag = ModConfig.AutoEquipOnOneHanded.Value; if (!flag && ModConfig.EquipAfterRanged.Value && previousWasRangedOrTwoHanded) { flag = true; } if (flag && (leftItem == null || (int)leftItem.m_shared.m_itemType == 5) && (leftItem == null || (int)leftItem.m_shared.m_itemType != 5)) { ItemData val = SelectShield(player); if (val != null) { EquipSilent((Humanoid)(object)player, val); } } } } } internal static bool IsSheathed(Humanoid humanoid) { if ((Object)(object)humanoid != (Object)null && humanoid.GetRightItem() == null) { return humanoid.m_hiddenRightItem != null; } return false; } internal static bool ShieldStillAttachedWhileSheathed(Humanoid humanoid) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Invalid comparison between Unknown and I4 if (!IsSheathed(humanoid)) { return false; } ItemData leftItem = humanoid.GetLeftItem(); if (leftItem?.m_shared != null && (int)leftItem.m_shared.m_itemType == 5) { return true; } ItemData hiddenLeftItem = humanoid.m_hiddenLeftItem; if (hiddenLeftItem?.m_shared != null) { return (int)hiddenLeftItem.m_shared.m_itemType == 5; } return false; } internal static void RetractShieldWhileSheathed(Humanoid humanoid) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 if ((Object)(object)humanoid == (Object)null) { return; } ItemData leftItem = humanoid.GetLeftItem(); if (leftItem?.m_shared != null && (int)leftItem.m_shared.m_itemType == 5) { UnequipSilent(humanoid, leftItem); } ItemData hiddenLeftItem = humanoid.m_hiddenLeftItem; if (hiddenLeftItem?.m_shared != null && (int)hiddenLeftItem.m_shared.m_itemType == 5) { humanoid.m_hiddenLeftItem = null; } VisEquipment visEquipment = humanoid.m_visEquipment; if (!((Object)(object)visEquipment == (Object)null)) { visEquipment.SetLeftBackItem(0, 0, 0); if ((Object)(object)visEquipment.m_leftBackItemInstance != (Object)null) { Object.Destroy((Object)(object)visEquipment.m_leftBackItemInstance); visEquipment.m_leftBackItemInstance = null; visEquipment.m_currentLeftBackItemHash = 0; visEquipment.m_currentLeftBackItemVariant = 0; visEquipment.m_currentLeftBackItemQuality = 0; } humanoid.SetupVisEquipment(visEquipment, false); visEquipment.UpdateEquipmentVisuals(); } } internal static void UnequipSilentPublic(Humanoid player, ItemData item) { UnequipSilent(player, item); } private static bool IsOneHandedWeapon(ItemData item) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 return (int)item.m_shared.m_itemType == 3; } private static bool IsRangedOrTwoHanded(ItemType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 if ((int)type != 4 && (int)type != 14 && (int)type != 22) { return (int)type == 20; } return true; } private static bool WeaponAllowed(ItemData weapon) { string value = ModConfig.AllowedWeaponTypes.Value; if (string.IsNullOrWhiteSpace(value)) { return true; } string value2 = PrefabName(weapon); string value3 = ((object)Unsafe.As<ItemType, ItemType>(ref weapon.m_shared.m_itemType)/*cast due to .constrained prefix*/).ToString(); string value4 = ((object)Unsafe.As<SkillType, SkillType>(ref weapon.m_shared.m_skillType)/*cast due to .constrained prefix*/).ToString(); foreach (string item in SplitList(value)) { if (item.Equals(value3, StringComparison.OrdinalIgnoreCase) || item.Equals(value4, StringComparison.OrdinalIgnoreCase) || item.Equals(value2, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static ItemData SelectShield(Player player) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Invalid comparison between Unknown and I4 List<ItemData> allItems = ((Humanoid)player).GetInventory().GetAllItems(); HashSet<string> hashSet = new HashSet<string>(SplitList(ModConfig.BlacklistShields.Value), StringComparer.OrdinalIgnoreCase); string text = (ModConfig.SelectionMode.Value ?? "Best").Trim(); string text2 = (ModConfig.PreferredShield.Value ?? "").Trim(); ItemData val = null; float num = float.MinValue; for (int i = 0; i < allItems.Count; i++) { ItemData val2 = allItems[i]; if (val2?.m_shared == null || (int)val2.m_shared.m_itemType != 5) { continue; } string text3 = PrefabName(val2); if (hashSet.Contains(text3)) { continue; } if (text.Equals("Preferred", StringComparison.OrdinalIgnoreCase) && text2.Length > 0) { if (text3.Equals(text2, StringComparison.OrdinalIgnoreCase)) { return val2; } continue; } if (text.Equals("First", StringComparison.OrdinalIgnoreCase)) { return val2; } float num2 = val2.m_shared.m_blockPower + val2.m_shared.m_timedBlockBonus; if (val == null || num2 > num) { val = val2; num = num2; } } if (val == null && text.Equals("Preferred", StringComparison.OrdinalIgnoreCase)) { return SelectFallbackBest(allItems, hashSet); } return val; } private static ItemData SelectFallbackBest(List<ItemData> items, HashSet<string> banned) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 ItemData val = null; float num = float.MinValue; for (int i = 0; i < items.Count; i++) { ItemData val2 = items[i]; if (val2?.m_shared != null && (int)val2.m_shared.m_itemType == 5 && !banned.Contains(PrefabName(val2))) { float num2 = val2.m_shared.m_blockPower + val2.m_shared.m_timedBlockBonus; if (val == null || num2 > num) { val = val2; num = num2; } } } return val; } private static void EquipSilent(Humanoid player, ItemData item) { InternalChange = true; try { player.EquipItem(item, false); } finally { InternalChange = false; } } private static void UnequipSilent(Humanoid player, ItemData item) { InternalChange = true; try { player.UnequipItem(item, false); } finally { InternalChange = false; } } private static string PrefabName(ItemData item) { if ((Object)(object)item.m_dropPrefab != (Object)null) { return ((Object)item.m_dropPrefab).name; } return item.m_shared.m_name ?? ""; } private static List<string> SplitList(string raw) { List<string> list = new List<string>(); if (string.IsNullOrWhiteSpace(raw)) { return list; } string[] array = raw.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } return list; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }