Decompiled source of FoodHighlighter v1.0.2

FoodHighlighter.dll

Decompiled 3 hours ago
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<bool> Enabled;

	internal static ConfigEntry<float> 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<bool>("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<float>("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<Food> 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<string> hashSet = new HashSet<string>();
		HashSet<string> hashSet2 = new HashSet<string>();
		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<ItemData> 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<Outline>();
				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<Outline>();
		if (!on)
		{
			if ((Object)(object)val != (Object)null)
			{
				((Behaviour)val).enabled = false;
			}
			return;
		}
		if ((Object)(object)val == (Object)null)
		{
			val = go.AddComponent<Outline>();
		}
		((Shadow)val).effectColor = col;
		((Shadow)val).effectDistance = new Vector2(thickness, thickness);
		((Shadow)val).useGraphicAlpha = false;
		((Behaviour)val).enabled = true;
	}
}