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 SmartPickupWarnings v1.0.0
BepInEx/plugins/SmartPickupWarnings/SmartPickupWarnings.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Shared.BasePlugin; using Shared.Localization; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = "")] [assembly: AssemblyCompany("SmartPickupWarnings")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0")] [assembly: AssemblyProduct("SmartPickupWarnings")] [assembly: AssemblyTitle("SmartPickupWarnings")] [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; } } } internal static class PluginInfo { public const string GUID = "rutabaga.smartpickupwarnings"; public const string NAME = "SmartPickupWarnings"; public const string VERSION = "1.0"; } namespace SmartPickupWarnings { public static class ConfigManager { public enum ENotificationReason { Space, Weight } private const string SectionNotification = "Notification"; private const string SectionCursor = "Cursor hover"; private static ConfigEntry<string> _messagePosition; private static ConfigEntry<bool> _enableInventoryFull; private static ConfigEntry<bool> _enableTooHeavy; private static ConfigEntry<bool> _hideWeightNotificationIfAlreadyOverweighted; private static ConfigEntry<bool> _showIcon; private static ConfigEntry<bool> _enableCursorInventoryFull; private static ConfigEntry<bool> _enableCursorTooHeavy; private static ConfigEntry<Color> _cursorColorNoSpace; private static ConfigEntry<Color> _cursorColorTooHeavy; private static ConfigEntry<bool> _hideWeightWarningOnCursorIfAlreadyOverweighted; private static bool _initialized; public static string MessagePosition => _messagePosition?.Value; public static bool EnableInventoryFull { get { if (_enableInventoryFull != null) { return _enableInventoryFull.Value; } return true; } } public static bool EnableTooHeavy { get { if (_enableTooHeavy != null) { return _enableTooHeavy.Value; } return true; } } public static bool EnableCursorInventoryFull { get { if (_enableCursorInventoryFull != null) { return _enableCursorInventoryFull.Value; } return true; } } public static bool EnableCursorTooHeavy { get { if (_enableCursorTooHeavy != null) { return _enableCursorTooHeavy.Value; } return true; } } public static bool ShowIcon { get { if (_showIcon != null) { return _showIcon.Value; } return true; } } public static bool HideWeightNotificationsIfAlreadyOverweighted { get { if (_hideWeightNotificationIfAlreadyOverweighted != null) { return _hideWeightNotificationIfAlreadyOverweighted.Value; } return true; } } public static bool HideWeightWarningOnCursorIfAlreadyOverweighted { get { if (_hideWeightWarningOnCursorIfAlreadyOverweighted != null) { return _hideWeightWarningOnCursorIfAlreadyOverweighted.Value; } return true; } } public static void Init(BaseUnityPlugin plugin) { //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) if (!_initialized) { _initialized = true; _messagePosition = plugin.Config.Bind<string>("Notification", "MessagePosition", "Center", "Position where HUD messages are displayed. Allowed: Center, TopLeft"); _enableInventoryFull = plugin.Config.Bind<bool>("Notification", "EnableInventoryFull", true, "Enable Inventory Full notifications"); _enableTooHeavy = plugin.Config.Bind<bool>("Notification", "EnableTooHeavy", true, "Enable Too Heavy notifications"); _hideWeightNotificationIfAlreadyOverweighted = plugin.Config.Bind<bool>("Notification", "HideWeightNotificationIfAlreadyOverweighted", true, "Hide weight notifications if the player is already overweighted"); _showIcon = plugin.Config.Bind<bool>("Notification", "ShowIcon", true, "Show item icon in the HUD message when available"); _enableCursorInventoryFull = plugin.Config.Bind<bool>("Cursor hover", "EnableCursorNoSpace", true, "Cursor hud shows when there is not enough space to take the hovered object"); _cursorColorNoSpace = plugin.Config.Bind<Color>("Cursor hover", "ColorNoSpace", new Color(67f / 85f, 0.3529412f, 23f / 85f), "Color of the cursor when hovering a pickup object and the inventory is full"); _enableCursorTooHeavy = plugin.Config.Bind<bool>("Cursor hover", "EnableCursorTooHeavy", true, "Cursor hud shows when the hovered object is too heavy for the inventory"); _cursorColorTooHeavy = plugin.Config.Bind<Color>("Cursor hover", "ColorTooHeavy", Color.yellow, "Color of the cursor when hovering a pickup object that is too heavy for the inventory"); _hideWeightWarningOnCursorIfAlreadyOverweighted = plugin.Config.Bind<bool>("Notification", "HideWeightWarningOnCursorIfAlreadyOverweighted", false, "Hide weight notifications if the player is already overweighted"); } } public static Color GetCrosshairColor(ENotificationReason a_reason) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) return (Color)(a_reason switch { ENotificationReason.Space => ((??)_cursorColorNoSpace?.Value) ?? new Color(201f, 90f, 69f), ENotificationReason.Weight => _cursorColorTooHeavy?.Value ?? Color.yellow, _ => Color.white, }); } } [BepInPlugin("rutabaga.smartpickupwarnings", "SmartPickupWarnings", "1.0")] public class SmartPickupWarnings : AValheimModPlugin { protected override void Initialize() { ConfigManager.Init((BaseUnityPlugin)(object)this); } protected override void Cleanup() { } } } namespace SmartPickupWarnings.Localization { public static class LocalizationData { public const string INVENTORY_FULL_MESSAGE_KEY = "InventoryFull"; public const string TOO_HEAVY_MESSAGE_KEY = "TooHeavy"; public const string CURSOR_INVENTORY_FULL_KEY = "CursorInventoryFull"; public const string CURSOR_TOO_HEAVY_KEY = "CursorTooHeavy"; } } namespace SmartPickupWarnings.Behaviours { [HarmonyPatch(typeof(Player), "AutoPickup")] public static class AutoPickupPatch { private static MethodInfo _canAddItemMethod = AccessTools.Method(typeof(Inventory), "CanAddItem", new Type[2] { typeof(ItemData), typeof(int) }, (Type[])null); private static MethodInfo _canAddItemCustomMethod = AccessTools.Method(typeof(CanAddItemHandler), "CanAddItemWithFeedback", (Type[])null, (Type[])null); private static FieldInfo _inventoryField = AccessTools.Field(typeof(Humanoid), "m_inventory"); private static FieldInfo _itemDataField = AccessTools.Field(typeof(ItemDrop), "m_itemData"); [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> a_instructions) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown if (!ValidateReflectionDependencies(out var a_logMessage)) { AValheimModPlugin.Log.LogError((object)(a_logMessage + "\nAborting repair all, fallback to vanilla behaviour.")); return a_instructions; } CodeMatcher val = new CodeMatcher(a_instructions, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Callvirt, (object)_canAddItemMethod, (string)null) }); val.SetInstruction(new CodeInstruction(OpCodes.Call, (object)_canAddItemCustomMethod)); if (!val.IsValid) { AValheimModPlugin.Log.LogError((object)"Couldn't find Inventory.CanAddItem call in Player.AutoPickup."); return a_instructions; } return val.InstructionEnumeration(); } private static bool ValidateReflectionDependencies(out string a_logMessage) { if (_canAddItemMethod == null) { a_logMessage = "Failed to find CanAddItem method in Inventory class."; return false; } if (_canAddItemCustomMethod == null) { a_logMessage = "Failed to find CanAddItemWithFeedback custom method in CanAddItemHandler class."; return false; } if (_inventoryField == null) { a_logMessage = "Failed to find m_inventory field in Humanoid class."; return false; } if (_itemDataField == null) { a_logMessage = "Failed to find m_itemData field in ItemDrop class."; return false; } a_logMessage = string.Empty; return true; } } public static class CanAddItemHandler { private static float m_oldInventoryWeight; private static float m_oldPlayerMaxWeight; internal static bool CanAddItemWithFeedback(Inventory a_inventory, ItemData a_item, int a_stack) { bool a_forceNotification = false; if (!Mathf.Approximately(m_oldInventoryWeight, a_inventory.GetTotalWeight()) || !Mathf.Approximately(m_oldPlayerMaxWeight, Player.m_localPlayer.GetMaxCarryWeight())) { a_forceNotification = true; } m_oldInventoryWeight = a_inventory.GetTotalWeight(); m_oldPlayerMaxWeight = Player.m_localPlayer.GetMaxCarryWeight(); bool num = a_inventory.CanAddItem(a_item, a_stack); bool flag = a_inventory.GetTotalWeight() + a_item.GetWeight(-1) <= Player.m_localPlayer.GetMaxCarryWeight(); bool flag2 = a_inventory.GetTotalWeight() > Player.m_localPlayer.GetMaxCarryWeight(); if (!num) { FeedbackManager.NotifyInventoryFull(a_item); } else if (!flag && (!flag2 || !ConfigManager.HideWeightNotificationsIfAlreadyOverweighted)) { FeedbackManager.NotifyTooHeavy(a_item, a_forceNotification); } return num && flag; } } public static class FeedbackManager { private static bool _hasNotified; public static void NotifyInventoryFull(ItemData a_itemData) { if (ConfigManager.EnableInventoryFull) { string localizedText = LocalizationManager.GetLocalizedText("InventoryFull"); NotifyMessage(a_itemData, localizedText); } } public static void NotifyTooHeavy(ItemData a_itemData, bool a_forceNotification = false) { if (ConfigManager.EnableTooHeavy) { string localizedText = LocalizationManager.GetLocalizedText("TooHeavy"); localizedText = string.Format(localizedText, a_itemData.m_shared.m_name); NotifyMessage(a_itemData, localizedText, a_forceNotification); } } private static void NotifyMessage(ItemData a_itemData, string a_message, bool a_forceNotification = false) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (_hasNotified && !a_forceNotification) { return; } if (a_itemData == null) { AValheimModPlugin.Log.LogError((object)"FeedbackManager.NotifyInventoryFull: m_itemData is null. Cannot display feedback message."); return; } if ((Object)(object)MessageHud.instance == (Object)null) { AValheimModPlugin.Log.LogError((object)"FeedbackManager.NotifyInventoryFull: MessageHud.instance is null. Cannot display feedback message."); return; } string a = ConfigManager.MessagePosition ?? "Center"; MessageType val = (MessageType)2; if (string.Equals(a, "TopLeft", StringComparison.OrdinalIgnoreCase)) { val = (MessageType)1; } if (ConfigManager.ShowIcon) { Sprite icon = a_itemData.GetIcon(); MessageHud.instance.ShowMessage(val, a_message, 0, icon, false, true); } else { MessageHud.instance.ShowMessage(val, a_message, 0, (Sprite)null, false, true); } _hasNotified = true; } public static void ResetNotification() { _hasNotified = false; } } [HarmonyPatch(typeof(Hud), "UpdateCrosshair")] public static class HudHoverPatch { [HarmonyPostfix] private static void Postfix() { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) GameObject hoverObject = ((Humanoid)Player.m_localPlayer).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { return; } ItemDrop component = hoverObject.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null) { return; } Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory(); if (inventory == null) { AValheimModPlugin.Log.LogError((object)"HudHoverPatch.Postfix: Player has no inventory"); return; } bool flag = inventory.CanAddItem(component.m_itemData, -1); bool flag2 = inventory.GetTotalWeight() + component.m_itemData.GetWeight(-1) <= Player.m_localPlayer.GetMaxCarryWeight(); bool flag3 = inventory.GetTotalWeight() >= Player.m_localPlayer.GetMaxCarryWeight(); if ((!flag || (!flag2 && (!flag3 || !ConfigManager.HideWeightWarningOnCursorIfAlreadyOverweighted))) && (flag || ConfigManager.EnableCursorInventoryFull) && (!flag2 || ConfigManager.EnableCursorTooHeavy)) { Color crosshairColor = ConfigManager.GetCrosshairColor(flag ? ConfigManager.ENotificationReason.Weight : ConfigManager.ENotificationReason.Space); string text = ColorUtility.ToHtmlStringRGBA(crosshairColor); string localizedText = LocalizationManager.GetLocalizedText(flag ? "CursorTooHeavy" : "CursorInventoryFull"); string text2 = "<color=#" + text + ">" + localizedText + "</color>"; if ((Object)(object)Hud.instance == (Object)null) { AValheimModPlugin.Log.LogError((object)"HudHoverPatch.Postfix: Hud instance is null"); return; } TextMeshProUGUI hoverName = Hud.instance.m_hoverName; ((TMP_Text)hoverName).text = ((TMP_Text)hoverName).text + "\n" + text2; ((Graphic)Hud.instance.m_crosshair).color = crosshairColor; } } } [HarmonyPatch(typeof(Inventory), "Changed")] public class InventoryChangedPatch { [HarmonyPostfix] private static void InventoryChangedPostfix(Inventory __instance) { FeedbackManager.ResetNotification(); } } } namespace Shared.Localization { internal static class LocalizationManager { private const string FALLBACK_LANGUAGE = "English"; public const string ENGLISH_KEY = "English"; public const string SWEDISH_KEY = "Swedish"; public const string FRENCH_KEY = "French"; public const string ITALIAN_KEY = "Italian"; public const string GERMAN_KEY = "German"; public const string SPANISH_KEY = "Spanish"; public const string RUSSIAN_KEY = "Russian"; public const string ROMANIAN_KEY = "Romanian"; public const string BULGARIAN_KEY = "Bulgarian"; public const string MACEDONIAN_KEY = "Macedonian"; public const string FINNISH_KEY = "Finnish"; public const string DANISH_KEY = "Danish"; public const string NORWEGIAN_KEY = "Norwegian"; public const string ICELANDIC_KEY = "Icelandic"; public const string TURKISH_KEY = "Turkish"; public const string LITHUANIAN_KEY = "Lithuanian"; public const string CZECH_KEY = "Czech"; public const string HUNGARIAN_KEY = "Hungarian"; public const string SLOVAK_KEY = "Slovak"; public const string POLISH_KEY = "Polish"; public const string DUTCH_KEY = "Dutch"; public const string PORTUGUESE_EUROPEAN_KEY = "Portuguese_European"; public const string PORTUGUESE_BRAZILIAN_KEY = "Portuguese_Brazilian"; public const string CHINESE_KEY = "Chinese"; public const string CHINESE_TRAD_KEY = "Chinese_Trad"; public const string JAPANESE_KEY = "Japanese"; public const string KOREAN_KEY = "Korean"; public const string HINDI_KEY = "Hindi"; public const string THAI_KEY = "Thai"; public const string ABENAKI_KEY = "Abenaki"; public const string CROATIAN_KEY = "Croatian"; public const string GEORGIAN_KEY = "Georgian"; public const string GREEK_KEY = "Greek"; public const string SERBIAN_KEY = "Serbian"; public const string UKRAINIAN_KEY = "Ukrainian"; public const string LATVIAN_KEY = "Latvian"; private static readonly Dictionary<string, Dictionary<string, string>> _translations = new Dictionary<string, Dictionary<string, string>>(); public static void Initialize() { LoadTranslations(); } private static void LoadTranslations() { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { if (!text.Contains(".Localization.Translations.") || !text.EndsWith(".json")) { continue; } string text2 = ExtractLanguageFromPath(text); using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { AValheimModPlugin.Log.LogWarning((object)("Failed to load translations for language " + text2 + ". The resource " + text + " could not be found.")); continue; } using StreamReader streamReader = new StreamReader(stream); Dictionary<string, string> dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(streamReader.ReadToEnd()); if (dictionary == null) { AValheimModPlugin.Log.LogWarning((object)("Failed to load translations for language " + text2 + ". The JSON file " + text + " is empty or invalid.")); } else { _translations[text2] = dictionary; } } } private static string ExtractLanguageFromPath(string a_resourceName) { return a_resourceName.Split(new char[1] { '.' })[^2]; } public static string GetLocalizedText(string a_key) { Localization instance = Localization.instance; if (instance == null) { AValheimModPlugin.Log.LogWarning((object)"Localization instance is null. Returning key as fallback."); return a_key; } string selectedLanguage = instance.GetSelectedLanguage(); if (_translations.TryGetValue(selectedLanguage, out var value) && value.TryGetValue(a_key, out var value2)) { return value2; } AValheimModPlugin.Log.LogWarning((object)("Can't find given language " + selectedLanguage + ". Fallback to english.")); if (_translations.TryGetValue("English", out var value3)) { if (value3.TryGetValue(a_key, out var value4)) { return value4; } AValheimModPlugin.Log.LogWarning((object)("Can't find translation for key " + a_key + " in " + selectedLanguage + " and English. Returning key as fallback.")); return a_key; } AValheimModPlugin.Log.LogWarning((object)"Can't find fallback language English.Returning key as fallback."); return a_key; } } } namespace Shared.BasePlugin { public abstract class AValheimModPlugin : BaseUnityPlugin { private Harmony _harmony; internal static ManualLogSource Log { get; private set; } protected abstract void Initialize(); protected abstract void Cleanup(); private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; LocalizationManager.Initialize(); Initialize(); _harmony = new Harmony("rutabaga.smartpickupwarnings"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SmartPickupWarnings 1.0 loaded!"); } private void OnDestroy() { Cleanup(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } }