Decompiled source of ExtraFoodSlot v1.0.8

BepInEx/plugins/nick008extrafood.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Nick008ExtraFood;

[BepInPlugin("nick008.extrafood", "nick008extrafood", "1.0.8")]
[BepInProcess("valheim.exe")]
public sealed class Nick008ExtraFoodPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(Player), "CanEat")]
	private static class PlayerCanEatPatch
	{
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			return ReplaceSingleFoodLimit(instructions, "Player.CanEat");
		}
	}

	[HarmonyPatch(typeof(Player), "EatFood")]
	private static class PlayerEatFoodPatch
	{
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			return ReplaceSingleFoodLimit(instructions, "Player.EatFood");
		}
	}

	[HarmonyPatch(typeof(Hud), "UpdateFood")]
	private static class HudUpdateFoodBackgroundPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			if (!((Object)(object)fourthFoodBackgroundObject == (Object)null) && !((Object)(object)fourthFoodIconObject == (Object)null))
			{
				bool activeSelf = fourthFoodIconObject.activeSelf;
				if (fourthFoodBackgroundObject.activeSelf != activeSelf)
				{
					fourthFoodBackgroundObject.SetActive(activeSelf);
				}
			}
		}
	}

	[HarmonyPatch(typeof(Hud), "Awake")]
	private static class HudAwakePatch
	{
		[HarmonyPostfix]
		private static void Postfix(Hud __instance)
		{
			TryAddFourthHudSlot(__instance);
		}
	}

	public const string PluginGuid = "nick008.extrafood";

	public const string PluginName = "nick008extrafood";

	public const string PluginVersion = "1.0.8";

	internal static ManualLogSource Log;

	private Harmony harmony;

	private static GameObject fourthFoodBackgroundObject;

	private static GameObject fourthFoodIconObject;

	private void Awake()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		harmony = new Harmony("nick008.extrafood");
		harmony.PatchAll();
		Log.LogInfo((object)"[nick008extrafood] Loaded. Fixed food limit: 4.");
	}

	private void OnDestroy()
	{
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}

	internal static IEnumerable<CodeInstruction> ReplaceSingleFoodLimit(IEnumerable<CodeInstruction> instructions, string methodName)
	{
		List<CodeInstruction> list = new List<CodeInstruction>(instructions);
		int num = 0;
		int index = -1;
		for (int i = 0; i < list.Count; i++)
		{
			if (list[i].opcode == OpCodes.Ldc_I4_3)
			{
				num++;
				index = i;
			}
		}
		if (num != 1)
		{
			if (Log != null)
			{
				Log.LogWarning((object)("[nick008extrafood] " + methodName + " changed (expected one ldc.i4.3, found " + num + "). Gameplay patch skipped for safety."));
			}
			return list;
		}
		list[index].opcode = OpCodes.Ldc_I4_4;
		list[index].operand = null;
		if (Log != null)
		{
			Log.LogInfo((object)("[nick008extrafood] Patched " + methodName + " food limit 3 -> 4."));
		}
		return list;
	}

	internal static void TryAddFourthHudSlot(Hud hud)
	{
		GameObject cloneObject = null;
		GameObject cloneObject2 = null;
		GameObject cloneObject3 = null;
		GameObject val = null;
		try
		{
			if ((Object)(object)hud == (Object)null)
			{
				return;
			}
			BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
			FieldInfo field = typeof(Hud).GetField("m_foodBars", bindingAttr);
			FieldInfo field2 = typeof(Hud).GetField("m_foodIcons", bindingAttr);
			FieldInfo field3 = typeof(Hud).GetField("m_foodTime", bindingAttr);
			if (field == null || field2 == null || field3 == null)
			{
				Log.LogWarning((object)"[nick008extrafood] HUD fields were not found. HUD patch skipped safely.");
				return;
			}
			Array array = field.GetValue(hud) as Array;
			Array array2 = field2.GetValue(hud) as Array;
			Array array3 = field3.GetValue(hud) as Array;
			if (array == null || array2 == null || array3 == null)
			{
				Log.LogWarning((object)"[nick008extrafood] HUD arrays are unavailable. HUD patch skipped safely.");
				return;
			}
			if (array.Length >= 4 && array2.Length >= 4 && array3.Length >= 4)
			{
				Log.LogInfo((object)"[nick008extrafood] HUD already has at least 4 food slots; no clone needed.");
				return;
			}
			if (array.Length != 3 || array2.Length != 3 || array3.Length != 3)
			{
				Log.LogWarning((object)("[nick008extrafood] Unexpected HUD array sizes (" + array.Length + "/" + array2.Length + "/" + array3.Length + "). HUD patch skipped safely."));
				return;
			}
			object? value = array.GetValue(0);
			Component val2 = (Component)((value is Component) ? value : null);
			object? value2 = array.GetValue(1);
			Component val3 = (Component)((value2 is Component) ? value2 : null);
			object? value3 = array.GetValue(2);
			Component val4 = (Component)((value3 is Component) ? value3 : null);
			object? value4 = array2.GetValue(0);
			Component val5 = (Component)((value4 is Component) ? value4 : null);
			object? value5 = array2.GetValue(1);
			Component val6 = (Component)((value5 is Component) ? value5 : null);
			object? value6 = array2.GetValue(2);
			Component val7 = (Component)((value6 is Component) ? value6 : null);
			object? value7 = array3.GetValue(0);
			Component val8 = (Component)((value7 is Component) ? value7 : null);
			object? value8 = array3.GetValue(1);
			Component val9 = (Component)((value8 is Component) ? value8 : null);
			object? value9 = array3.GetValue(2);
			Component val10 = (Component)((value9 is Component) ? value9 : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null || (Object)(object)val7 == (Object)null || (Object)(object)val8 == (Object)null || (Object)(object)val9 == (Object)null || (Object)(object)val10 == (Object)null)
			{
				Log.LogWarning((object)"[nick008extrafood] Vanilla food HUD components are missing. HUD patch skipped safely.");
				return;
			}
			Component val11 = CloneFourthAboveTop(val2, val3, val4, "nick008extrafood_foodBar4", out cloneObject);
			Component val12 = CloneFourthAboveTop(val5, val6, val7, "nick008extrafood_foodIcon4", out cloneObject2);
			Component val13 = CloneFourthAboveTop(val8, val9, val10, "nick008extrafood_foodTime4", out cloneObject3);
			if ((Object)(object)val11 == (Object)null || (Object)(object)val12 == (Object)null || (Object)(object)val13 == (Object)null)
			{
				DestroyIfCreated(cloneObject);
				DestroyIfCreated(cloneObject2);
				DestroyIfCreated(cloneObject3);
				Log.LogWarning((object)"[nick008extrafood] Could not clone all three HUD components. HUD patch skipped safely.");
				return;
			}
			Array value10 = GrowArrayToFour(array, val11);
			Array value11 = GrowArrayToFour(array2, val12);
			Array value12 = GrowArrayToFour(array3, val13);
			field.SetValue(hud, value10);
			field2.SetValue(hud, value11);
			field3.SetValue(hud, value12);
			Component visuallyTop = GetVisuallyTop(val5, val6, val7);
			val = CloneBackgroundOnly(visuallyTop, cloneObject2);
			cloneObject.SetActive(false);
			cloneObject2.SetActive(false);
			cloneObject3.SetActive(false);
			if ((Object)(object)val != (Object)null)
			{
				val.SetActive(false);
				fourthFoodBackgroundObject = val;
				fourthFoodIconObject = cloneObject2;
				Log.LogInfo((object)"[nick008extrafood] Fourth food background cloned without foreground children.");
			}
			else
			{
				fourthFoodBackgroundObject = null;
				fourthFoodIconObject = cloneObject2;
				Log.LogWarning((object)"[nick008extrafood] Fourth slot works, but cosmetic background could not be cloned.");
			}
			Log.LogInfo((object)"[nick008extrafood] HUD expanded from 3 to 4 food slots (Valheim 1.0 layout).");
		}
		catch (Exception ex)
		{
			DestroyIfCreated(cloneObject);
			DestroyIfCreated(cloneObject2);
			DestroyIfCreated(cloneObject3);
			DestroyIfCreated(val);
			fourthFoodBackgroundObject = null;
			fourthFoodIconObject = null;
			if (Log != null)
			{
				Log.LogError((object)("[nick008extrafood] HUD patch failed safely: " + ex));
			}
		}
	}

	private static Component GetVisuallyTop(Component first, Component second, Component third)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		Component val = first;
		if ((Object)(object)second != (Object)null && ((Object)(object)val == (Object)null || second.transform.position.y > val.transform.position.y))
		{
			val = second;
		}
		if ((Object)(object)third != (Object)null && ((Object)(object)val == (Object)null || third.transform.position.y > val.transform.position.y))
		{
			val = third;
		}
		return val;
	}

	private static GameObject CloneBackgroundOnly(Component topIcon, GameObject fourthIconObject)
	{
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if ((Object)(object)topIcon == (Object)null || (Object)(object)fourthIconObject == (Object)null || (Object)(object)topIcon.transform.parent == (Object)null)
			{
				return null;
			}
			Transform parent = topIcon.transform.parent;
			if ((Object)(object)parent.parent == (Object)null)
			{
				return null;
			}
			int siblingIndex = parent.GetSiblingIndex();
			GameObject val = Object.Instantiate<GameObject>(((Component)parent).gameObject, parent.parent, false);
			((Object)val).name = "nick008extrafood_foodBackground4";
			Vector3 val2 = fourthIconObject.transform.position - topIcon.transform.position;
			val.transform.position = parent.position + val2;
			for (int i = 0; i < val.transform.childCount; i++)
			{
				Transform child = val.transform.GetChild(i);
				if ((Object)(object)child != (Object)null)
				{
					((Component)child).gameObject.SetActive(false);
				}
			}
			val.transform.SetSiblingIndex(siblingIndex);
			return val;
		}
		catch (Exception ex)
		{
			if (Log != null)
			{
				Log.LogWarning((object)("[nick008extrafood] Background-only clone skipped safely: " + ex.Message));
			}
			return null;
		}
	}

	private static Component CloneFourthAboveTop(Component first, Component second, Component third, string cloneName, out GameObject cloneObject)
	{
		//IL_0029: 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_005b: 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_010c: Unknown result type (might be due to invalid IL or missing references)
		cloneObject = null;
		if ((Object)(object)first == (Object)null || (Object)(object)second == (Object)null || (Object)(object)third == (Object)null)
		{
			return null;
		}
		Component val = first;
		float num = first.transform.position.y;
		float num2 = num;
		float y = second.transform.position.y;
		if (y < num)
		{
			num = y;
		}
		if (y > num2)
		{
			num2 = y;
			val = second;
		}
		float y2 = third.transform.position.y;
		if (y2 < num)
		{
			num = y2;
		}
		if (y2 > num2)
		{
			num2 = y2;
			val = third;
		}
		float num3 = (num2 - num) * 0.5f;
		if (num3 <= 0.01f || (Object)(object)val.gameObject == (Object)null)
		{
			return null;
		}
		Transform parent = val.transform.parent;
		cloneObject = Object.Instantiate<GameObject>(val.gameObject, parent, false);
		((Object)cloneObject).name = cloneName;
		Component component = cloneObject.GetComponent(((object)val).GetType());
		if ((Object)(object)component == (Object)null)
		{
			Object.Destroy((Object)(object)cloneObject);
			cloneObject = null;
			return null;
		}
		Vector3 position = val.transform.position;
		position.y = num2 + num3;
		cloneObject.transform.position = position;
		cloneObject.transform.SetAsLastSibling();
		if (Log != null)
		{
			Log.LogInfo((object)("[nick008extrafood] " + cloneName + " Y min/max/spacing/target = " + num.ToString("F2") + "/" + num2.ToString("F2") + "/" + num3.ToString("F2") + "/" + position.y.ToString("F2")));
		}
		return component;
	}

	private static void DestroyIfCreated(GameObject gameObject)
	{
		if ((Object)(object)gameObject != (Object)null)
		{
			Object.Destroy((Object)(object)gameObject);
		}
	}

	private static Array GrowArrayToFour(Array original, object fourth)
	{
		Type elementType = original.GetType().GetElementType();
		Array array = Array.CreateInstance(elementType, 4);
		Array.Copy(original, array, 3);
		array.SetValue(fourth, 3);
		return array;
	}

	private static Component GetMatchingComponent(Transform cloneRoot, string relativePath, Type componentType)
	{
		Transform val = cloneRoot;
		if (!string.IsNullOrEmpty(relativePath))
		{
			val = cloneRoot.Find(relativePath);
		}
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		return ((Component)val).GetComponent(componentType);
	}

	private static string GetRelativePath(Transform root, Transform child)
	{
		if ((Object)(object)root == (Object)null || (Object)(object)child == (Object)null)
		{
			return null;
		}
		if ((Object)(object)root == (Object)(object)child)
		{
			return string.Empty;
		}
		List<string> list = new List<string>();
		Transform val = child;
		while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
		{
			list.Add(((Object)val).name);
			val = val.parent;
		}
		if ((Object)(object)val != (Object)(object)root)
		{
			return null;
		}
		list.Reverse();
		return string.Join("/", list.ToArray());
	}
}