using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace FoodHighlighter; [BepInPlugin("FoodHighlighter", "FoodHighlighter", "1.0.2")] public class FoodHighlighterPlugin : BaseUnityPlugin { public const string PluginGuid = "FoodHighlighter"; public const string PluginName = "FoodHighlighter"; public const string PluginVersion = "1.0.2"; internal static ConfigEntry Enabled; internal static ConfigEntry OutlineThickness; internal static ManualLogSource Log; internal static readonly FieldInfo ElementsField = AccessTools.Field(typeof(InventoryGrid), "m_elements"); internal static readonly Type ElementType = AccessTools.Inner(typeof(InventoryGrid), "Element"); internal static readonly FieldInfo ElemPosField = ((ElementType != null) ? AccessTools.Field(ElementType, "m_pos") : null); internal static readonly FieldInfo ElemFoodField = ((ElementType != null) ? AccessTools.Field(ElementType, "m_food") : null); internal static readonly FieldInfo MaxFoodsField = AccessTools.Field(typeof(Player), "m_maxFoods"); private void Awake() { //IL_0098: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Master switch. When on, the best food of each type (healing / stamina / mixed) you haven't eaten gets its fork icon outlined."); OutlineThickness = ((BaseUnityPlugin)this).Config.Bind("Appearance", "OutlineThickness", 1f, "Thickness (in pixels) of the outline."); if (ElementsField == null || ElementType == null || ElemPosField == null || ElemFoodField == null) { Log.LogError((object)"FoodHighlighter: could not resolve InventoryGrid internals; the mod is disabled. A game update may have changed the layout."); return; } new Harmony("FoodHighlighter").PatchAll(); Log.LogInfo((object)"FoodHighlighter v1.0.2 loaded."); } internal static Color Negative(Color c) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) return new Color(1f - c.r, 1f - c.g, 1f - c.b, 1f); } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] internal static class InventoryGrid_UpdateGui_Patch { private const int CatHealth = 0; private const int CatStamina = 1; private const int CatEitr = 2; private const int CatMixed = 3; private const int CatCount = 4; private static void Postfix(InventoryGrid __instance, Player player) { //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) try { if (FoodHighlighterPlugin.Enabled == null || !FoodHighlighterPlugin.Enabled.Value) { ClearAll(__instance); } else { if ((Object)(object)player == (Object)null) { return; } Inventory inventory = __instance.GetInventory(); if (inventory == null) { return; } if (inventory != ((Humanoid)player).GetInventory()) { ClearAll(__instance); return; } ItemData[] array = FindBestPerCategory(inventory, player); if (!(FoodHighlighterPlugin.ElementsField.GetValue(__instance) is IList list)) { return; } float value = FoodHighlighterPlugin.OutlineThickness.Value; for (int i = 0; i < list.Count; i++) { object obj = list[i]; if (obj == null) { continue; } object? value2 = FoodHighlighterPlugin.ElemFoodField.GetValue(obj); Image val = (Image)((value2 is Image) ? value2 : null); if ((Object)(object)val == (Object)null) { continue; } bool flag = false; if (array != null) { Vector2i val2 = (Vector2i)FoodHighlighterPlugin.ElemPosField.GetValue(obj); ItemData itemAt = inventory.GetItemAt(val2.x, val2.y); if (itemAt != null) { flag = IsBest(itemAt, array); } } Color col = FoodHighlighterPlugin.Negative(((Graphic)val).color); ApplyOutline(((Component)val).gameObject, flag, col, value); } } } catch (Exception ex) { if (FoodHighlighterPlugin.Log != null) { FoodHighlighterPlugin.Log.LogWarning((object)("FoodHighlighter UpdateGui error: " + ex.Message)); } } } private static ItemData[] FindBestPerCategory(Inventory inv, Player player) { ItemData[] array = (ItemData[])(object)new ItemData[4]; float[] array2 = new float[4]; List foods = player.GetFoods(); int num = 3; if (FoodHighlighterPlugin.MaxFoodsField != null) { object value = FoodHighlighterPlugin.MaxFoodsField.GetValue(player); if (value is int) { num = (int)value; } } bool flag = foods == null || foods.Count < num; HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(); if (foods != null) { for (int i = 0; i < foods.Count; i++) { Food val = foods[i]; if (val != null && !string.IsNullOrEmpty(val.m_name)) { hashSet.Add(val.m_name); if (val.CanEatAgain()) { hashSet2.Add(val.m_name); } } } } List allItems = inv.GetAllItems(); for (int j = 0; j < allItems.Count; j++) { ItemData val2 = allItems[j]; if (val2 == null || val2.m_shared == null) { continue; } float food = val2.m_shared.m_food; float foodStamina = val2.m_shared.m_foodStamina; float foodEitr = val2.m_shared.m_foodEitr; float num2 = food + foodStamina + foodEitr; if (num2 <= 0f) { continue; } string text = (((Object)(object)val2.m_dropPrefab != (Object)null) ? ((Object)val2.m_dropPrefab).name : null); if (text != null && hashSet.Contains(text)) { if (text == null || !hashSet2.Contains(text)) { continue; } } else if (!flag) { continue; } int num3 = ForkCategory(food, foodStamina, foodEitr); if (num2 > array2[num3]) { array2[num3] = num2; array[num3] = val2; } } return array; } private static int ForkCategory(float h, float s, float e) { if (h < e / 2f && s < e / 2f) { return 2; } if (s < h / 2f) { return 0; } if (h < s / 2f) { return 1; } return 3; } private static bool IsBest(ItemData item, ItemData[] best) { for (int i = 0; i < best.Length; i++) { if (best[i] != null && best[i] == item) { return true; } } return false; } private static void ClearAll(InventoryGrid grid) { if (!(FoodHighlighterPlugin.ElementsField.GetValue(grid) is IList list)) { return; } for (int i = 0; i < list.Count; i++) { object obj = list[i]; if (obj == null) { continue; } object? value = FoodHighlighterPlugin.ElemFoodField.GetValue(obj); Image val = (Image)((value is Image) ? value : null); if (!((Object)(object)val == (Object)null)) { Outline component = ((Component)val).gameObject.GetComponent(); if ((Object)(object)component != (Object)null) { ((Behaviour)component).enabled = false; } } } } private static void ApplyOutline(GameObject go, bool on, Color col, float thickness) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) Outline val = go.GetComponent(); if (!on) { if ((Object)(object)val != (Object)null) { ((Behaviour)val).enabled = false; } return; } if ((Object)(object)val == (Object)null) { val = go.AddComponent(); } ((Shadow)val).effectColor = col; ((Shadow)val).effectDistance = new Vector2(thickness, thickness); ((Shadow)val).useGraphicAlpha = false; ((Behaviour)val).enabled = true; } }