using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ExtraFoodSlots")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("HP")]
[assembly: AssemblyProduct("ExtraFoodSlots")]
[assembly: AssemblyCopyright("Copyright © HP 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("83294e72-4c43-4a61-8792-54257419a120")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace ExtraFoodSlots;
[BepInPlugin("youdied.extrafoodslots", "Extra Food Slots", "1.0.0")]
[BepInProcess("valheim.exe")]
public class ExtraFoodSlotsPlugin : BaseUnityPlugin
{
public const string PluginGUID = "youdied.extrafoodslots";
public const string PluginName = "Extra Food Slots";
public const string PluginVersion = "1.0.0";
public static ManualLogSource Log;
public static ConfigEntry<int> ExtraSlotCount;
private readonly Harmony _harmony = new Harmony("youdied.extrafoodslots");
private void Awake()
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
ExtraSlotCount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ExtraSlotCount", 1, new ConfigDescription("How many extra food slots to add (1-3). Can be changed in-game via the Config Manager.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 3), Array.Empty<object>()));
_harmony.PatchAll();
Log.LogInfo((object)string.Format("[EFS] Extra Food Slots v{0} loaded. ExtraSlots={1}", "1.0.0", ExtraSlotCount.Value));
}
private void OnDestroy()
{
_harmony.UnpatchSelf();
}
}
public static class ExtraFoodSlotsHUD
{
private class SlotUI
{
public RectTransform Root;
public Image TimerBar;
public Image Icon;
public TMP_Text Time;
}
private static readonly List<SlotUI> _slots = new List<SlotUI>();
private static Hud _builtFor = null;
private static bool _gaveUp = false;
private static int _builtCount = 0;
private const float SlotX = -67.15259f;
private const float SlotY0 = 57.998566f;
private const float SlotStep = 46f;
private const float SlotSize = 45f;
public static bool IsBuiltFor(Hud hud)
{
int value = ExtraFoodSlotsPlugin.ExtraSlotCount.Value;
if (_builtCount != value)
{
_gaveUp = false;
_builtFor = null;
}
return (Object)(object)_builtFor == (Object)(object)hud && _slots.Count == value;
}
public static void MarkDirty()
{
_builtFor = null;
_gaveUp = false;
}
public static void BuildSlots(Hud hud)
{
//IL_010b: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: 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)
//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
//IL_01ab: Expected O, but got Unknown
if (_gaveUp)
{
return;
}
foreach (SlotUI slot in _slots)
{
if ((Object)(object)slot.Root != (Object)null)
{
Object.Destroy((Object)(object)((Component)slot.Root).gameObject);
}
}
_slots.Clear();
int value = ExtraFoodSlotsPlugin.ExtraSlotCount.Value;
GameObject val = FindInChildren(((Component)hud).transform, "food0");
if ((Object)(object)val == (Object)null)
{
ExtraFoodSlotsPlugin.Log.LogWarning((object)"[EFS] Could not find 'food0' in HUD hierarchy.");
_gaveUp = true;
_builtFor = hud;
return;
}
RectTransform component = val.GetComponent<RectTransform>();
Transform parent = ((Transform)component).parent;
RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null);
for (int i = 0; i < value; i++)
{
GameObject val3 = Object.Instantiate<GameObject>(val, (Transform)(object)val2, false);
((Object)val3).name = $"EFS_food{3 + i}";
RectTransform component2 = val3.GetComponent<RectTransform>();
component2.anchorMin = component.anchorMin;
component2.anchorMax = component.anchorMax;
component2.pivot = component.pivot;
component2.sizeDelta = new Vector2(45f, 45f);
component2.anchoredPosition = new Vector2(-67.15259f, 57.998566f + 46f * (float)(3 + i));
((Transform)component2).SetAsLastSibling();
val3.SetActive(true);
Image component3 = val3.GetComponent<Image>();
Image val4 = null;
TMP_Text val5 = null;
foreach (Transform item in val3.transform)
{
Transform val6 = item;
if ((Object)(object)val4 == (Object)null)
{
val4 = ((Component)val6).GetComponent<Image>();
}
if ((Object)(object)val5 == (Object)null)
{
val5 = ((Component)val6).GetComponent<TMP_Text>();
}
}
_slots.Add(new SlotUI
{
Root = component2,
TimerBar = component3,
Icon = val4,
Time = val5
});
}
_builtFor = hud;
_builtCount = value;
ExtraFoodSlotsPlugin.Log.LogInfo((object)$"[EFS] Built {value} extra slot(s).");
}
public static void UpdateSlots(Player player)
{
//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_0170: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_025e: Unknown result type (might be due to invalid IL or missing references)
//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
if (_slots.Count == 0 || (Object)(object)player == (Object)null)
{
return;
}
List<Food> foods = player.GetFoods();
for (int i = 0; i < _slots.Count; i++)
{
SlotUI slotUI = _slots[i];
if ((Object)(object)slotUI.Root == (Object)null)
{
continue;
}
int num = 3 + i;
bool flag = num < foods.Count;
((Component)slotUI.Root).gameObject.SetActive(true);
if (flag)
{
Food val = foods[num];
float fillAmount = Mathf.Clamp01(val.m_time / val.m_item.m_shared.m_foodBurnTime);
if ((Object)(object)slotUI.TimerBar != (Object)null)
{
slotUI.TimerBar.fillAmount = fillAmount;
((Graphic)slotUI.TimerBar).color = new Color(0f, 0f, 0f, 0.503f);
}
if ((Object)(object)slotUI.Icon != (Object)null)
{
((Component)slotUI.Icon).gameObject.SetActive(true);
slotUI.Icon.sprite = val.m_item.GetIcon();
((Graphic)slotUI.Icon).color = (Color)(val.CanEatAgain() ? new Color(1f, 1f, 1f, 0.7f + Mathf.Sin(Time.time * 5f) * 0.3f) : Color.white);
}
if ((Object)(object)slotUI.Time != (Object)null)
{
((Component)slotUI.Time).gameObject.SetActive(true);
if (val.m_time >= 60f)
{
slotUI.Time.text = Mathf.CeilToInt(val.m_time / 60f) + "m";
((Graphic)slotUI.Time).color = Color.white;
}
else
{
slotUI.Time.text = Mathf.FloorToInt(val.m_time) + "s";
((Graphic)slotUI.Time).color = new Color(1f, 1f, 1f, 0.4f + Mathf.Sin(Time.time * 10f) * 0.6f);
}
}
}
else
{
if ((Object)(object)slotUI.TimerBar != (Object)null)
{
slotUI.TimerBar.fillAmount = 1f;
((Graphic)slotUI.TimerBar).color = new Color(0f, 0f, 0f, 0.2f);
}
if ((Object)(object)slotUI.Icon != (Object)null)
{
((Component)slotUI.Icon).gameObject.SetActive(false);
}
if ((Object)(object)slotUI.Time != (Object)null)
{
((Component)slotUI.Time).gameObject.SetActive(true);
slotUI.Time.text = "";
}
}
}
}
private static GameObject FindInChildren(Transform parent, string name)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Expected O, but got Unknown
foreach (Transform item in parent)
{
Transform val = item;
if (((Object)val).name == name)
{
return ((Component)val).gameObject;
}
GameObject val2 = FindInChildren(val, name);
if ((Object)(object)val2 != (Object)null)
{
return val2;
}
}
return null;
}
}
[HarmonyPatch(typeof(Player), "CanEat")]
public static class Patch_Player_CanEat
{
private static readonly FieldInfo FFoods = typeof(Player).GetField("m_foods", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
[HarmonyPrefix]
public static bool Prefix(Player __instance, ItemData item, bool showMessages, ref bool __result)
{
if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
{
return true;
}
if (FFoods == null)
{
return true;
}
List<Food> list = (List<Food>)FFoods.GetValue(__instance);
int count = list.Count;
int num = 3 + ExtraFoodSlotsPlugin.ExtraSlotCount.Value;
if (count < 3 || count >= num)
{
return true;
}
foreach (Food item2 in list)
{
if (item2.m_item.m_shared.m_name == item.m_shared.m_name)
{
if (item2.CanEatAgain())
{
__result = true;
return false;
}
if (showMessages)
{
((Character)__instance).Message((MessageType)2, Localization.instance.Localize("$msg_nomore", new string[1] { item.m_shared.m_name }), 0, (Sprite)null);
}
__result = false;
return false;
}
}
foreach (Food item3 in list)
{
if (item3.CanEatAgain())
{
__result = true;
return false;
}
}
__result = true;
return false;
}
}
[HarmonyPatch(typeof(Player), "EatFood")]
public static class Patch_Player_EatFood
{
private static readonly FieldInfo FFoods = typeof(Player).GetField("m_foods", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
[HarmonyPrefix]
public static bool Prefix(Player __instance, ItemData item, ref bool __result)
{
//IL_0197: Unknown result type (might be due to invalid IL or missing references)
//IL_019e: Expected O, but got Unknown
if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
{
return true;
}
if (FFoods == null)
{
return true;
}
List<Food> list = (List<Food>)FFoods.GetValue(__instance);
int count = list.Count;
if (count < 3)
{
return true;
}
foreach (Food item2 in list)
{
if (item2.m_item.m_shared.m_name == item.m_shared.m_name)
{
return true;
}
}
int num = 3 + ExtraFoodSlotsPlugin.ExtraSlotCount.Value;
if (count < num)
{
string text = "";
if (item.m_shared.m_food > 0f)
{
text += $" +{item.m_shared.m_food} $item_food_health ";
}
if (item.m_shared.m_foodStamina > 0f)
{
text += $" +{item.m_shared.m_foodStamina} $item_food_stamina ";
}
if (item.m_shared.m_foodEitr > 0f)
{
text += $" +{item.m_shared.m_foodEitr} $item_food_eitr ";
}
((Character)__instance).Message((MessageType)2, text, 0, (Sprite)null);
Food val = new Food();
val.m_name = (Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : item.m_shared.m_name);
val.m_item = item;
val.m_time = item.m_shared.m_foodBurnTime;
val.m_health = item.m_shared.m_food;
val.m_stamina = item.m_shared.m_foodStamina;
val.m_eitr = item.m_shared.m_foodEitr;
list.Add(val);
typeof(Player).GetMethod("UpdateFood", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(__instance, new object[2] { 0f, true });
__result = true;
return false;
}
return true;
}
}
[HarmonyPatch(typeof(Hud), "UpdateFood")]
public static class Patch_Hud_UpdateFood
{
[HarmonyPostfix]
public static void Postfix(Hud __instance, Player player)
{
if (!ExtraFoodSlotsHUD.IsBuiltFor(__instance))
{
ExtraFoodSlotsHUD.BuildSlots(__instance);
}
ExtraFoodSlotsHUD.UpdateSlots(player);
}
}