Decompiled source of SmartPickupWarnings v1.0.0

BepInEx/plugins/SmartPickupWarnings/SmartPickupWarnings.dll

Decompiled 2 weeks ago
using 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();
			}
		}
	}
}