Decompiled source of NoScrollWardrobes v0.2.0

NoScrollWardrobes.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("No Scroll Wardrobes")]
[assembly: AssemblyDescription("Shows containers too tall for the container panel, like the wardrobe, without a scrollbar.")]
[assembly: AssemblyCompany("falconnn")]
[assembly: AssemblyProduct("No Scroll Wardrobes")]
[assembly: AssemblyCopyright("Made by falconnn")]
[assembly: AssemblyFileVersion("0.2.0")]
[assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with the assistance of Generative AI (Claude Code, Anthropic's AI coding agent).")]
[assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic")]
[assembly: AssemblyVersion("0.2.0.0")]
namespace NoScrollWardrobes;

[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
internal static class ContainerLayout
{
	private struct Layout : IEquatable<Layout>
	{
		public readonly int Columns;

		public readonly int Rows;

		public readonly float Scale;

		public readonly bool IsVanilla;

		private Layout(int columns, int rows, float scale, bool isVanilla)
		{
			Columns = columns;
			Rows = rows;
			Scale = scale;
			IsVanilla = isVanilla;
		}

		public static Layout Vanilla(int width, int height)
		{
			return new Layout(width, height, 1f, isVanilla: true);
		}

		public static Layout Fit(int count, float space, float viewWidth, float viewHeight)
		{
			Layout result = default(Layout);
			int num = int.MaxValue;
			for (int num2 = count; num2 >= 1; num2--)
			{
				int num3 = (count + num2 - 1) / num2;
				float num4 = Mathf.Min(1f, Mathf.Min(viewWidth / ((float)num2 * space), viewHeight / ((float)num3 * space)));
				int num5 = num2 * num3 - count;
				if (result.Columns == 0 || num4 > result.Scale + 0.001f || (num4 > result.Scale - 0.001f && num5 < num))
				{
					result = new Layout(num2, num3, num4, isVanilla: false);
					num = num5;
				}
			}
			return result;
		}

		public bool Equals(Layout other)
		{
			if (Columns == other.Columns && Rows == other.Rows && Scale == other.Scale)
			{
				return IsVanilla == other.IsVanilla;
			}
			return false;
		}
	}

	private static readonly FieldRef<InventoryGui, InventoryGrid> ContainerGrid = AccessTools.FieldRefAccess<InventoryGui, InventoryGrid>("m_containerGrid");

	private static readonly FieldRef<InventoryGui, Container> CurrentContainer = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer");

	private static readonly FieldRef<InventoryGrid, List<InventoryElement>> Elements = AccessTools.FieldRefAccess<InventoryGrid, List<InventoryElement>>("m_elements");

	private static readonly FieldRef<InventoryGrid, int> GridWidth = AccessTools.FieldRefAccess<InventoryGrid, int>("m_width");

	private static readonly FieldRef<InventoryGrid, int> GridHeight = AccessTools.FieldRefAccess<InventoryGrid, int>("m_height");

	private static readonly FieldRef<Container, ZNetView> ContainerView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview");

	private static InventoryElement s_firstElement;

	private static int s_elementCount;

	private static Layout s_applied;

	private static float s_appliedWidth;

	private static InventoryGrid s_scrollOwner;

	private static ScrollRect s_scrollRect;

	private static Container s_prefabOwner;

	private static string s_prefabName;

	private static Container s_lastContainer;

	private static void Postfix(InventoryGrid __instance)
	{
		//IL_0065: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Expected O, but got Unknown
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Unknown result type (might be due to invalid IL or missing references)
		InventoryGui instance = InventoryGui.instance;
		if ((Object)(object)instance == (Object)null || (Object)(object)__instance != (Object)(object)ContainerGrid.Invoke(instance))
		{
			return;
		}
		List<InventoryElement> list = Elements.Invoke(__instance);
		if (list != null && list.Count != 0)
		{
			int width = GridWidth.Invoke(__instance);
			int num = GridHeight.Invoke(__instance);
			float elementSpace = __instance.m_elementSpace;
			RectTransform val = (RectTransform)((Component)__instance).transform;
			Rect rect = val.rect;
			float width2 = ((Rect)(ref rect)).width;
			float num2 = ViewportHeight(__instance, val);
			Container val2 = CurrentContainer.Invoke(instance);
			Layout layout = Layout.Vanilla(width, num);
			if ((Object)(object)val2 != (Object)null && width2 > 0f && num2 > 0f && IsTarget(val2, (float)num * elementSpace > num2))
			{
				layout = Layout.Fit(list.Count, elementSpace, width2, num2);
			}
			if ((Object)(object)val2 != (Object)(object)s_lastContainer)
			{
				s_lastContainer = val2;
				LogOpened(val2, width, num, elementSpace, width2, num2, layout);
			}
			if (!layout.IsVanilla)
			{
				__instance.m_gridRoot.SetSizeWithCurrentAnchors((Axis)1, (float)layout.Rows * elementSpace * layout.Scale);
			}
			if (!((Object)(object)list[0] == (Object)(object)s_firstElement) || list.Count != s_elementCount || !layout.Equals(s_applied) || width2 != s_appliedWidth)
			{
				Arrange(list, layout, elementSpace, width2);
				s_firstElement = list[0];
				s_elementCount = list.Count;
				s_applied = layout;
				s_appliedWidth = width2;
			}
		}
	}

	private static void Arrange(List<InventoryElement> elements, Layout layout, float space, float viewWidth)
	{
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		float num = space * layout.Scale;
		float num2 = viewWidth / 2f - (float)layout.Columns * num / 2f;
		Vector3 localScale = default(Vector3);
		((Vector3)(ref localScale))..ctor(layout.Scale, layout.Scale, 1f);
		for (int i = 0; i < elements.Count; i++)
		{
			RectTransform val = (RectTransform)((Component)elements[i]).transform;
			val.anchoredPosition = new Vector2(num2 + (float)(i % layout.Columns) * num, (float)(-(i / layout.Columns)) * num);
			((Transform)val).localScale = localScale;
		}
	}

	private static bool IsTarget(Container container, bool wouldScroll)
	{
		if (Plugin.ContainerNames.Contains(PrefabName(container)))
		{
			return true;
		}
		if (!wouldScroll)
		{
			return false;
		}
		if (!Plugin.ContainerNames.Contains("*"))
		{
			if (Plugin.Graves.Value)
			{
				return (Object)(object)((Component)container).GetComponent<TombStone>() != (Object)null;
			}
			return false;
		}
		return true;
	}

	private static string PrefabName(Container container)
	{
		if ((Object)(object)container != (Object)(object)s_prefabOwner)
		{
			s_prefabOwner = container;
			ZNetView val = ContainerView.Invoke(container);
			s_prefabName = Utils.GetPrefabName(((Object)(object)val != (Object)null) ? ((Component)val).gameObject : ((Component)container).gameObject);
		}
		return s_prefabName;
	}

	private static float ViewportHeight(InventoryGrid grid, RectTransform gridRect)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)s_scrollOwner != (Object)(object)grid)
		{
			s_scrollOwner = grid;
			s_scrollRect = ((Component)grid.m_gridRoot).GetComponentInParent<ScrollRect>();
		}
		Rect rect = gridRect.rect;
		float num = ((Rect)(ref rect)).height;
		if ((Object)(object)s_scrollRect != (Object)null && (Object)(object)s_scrollRect.viewport != (Object)null)
		{
			float num2 = num;
			rect = s_scrollRect.viewport.rect;
			num = Mathf.Min(num2, ((Rect)(ref rect)).height);
		}
		return num;
	}

	private static void LogOpened(Container container, int width, int height, float space, float viewWidth, float viewHeight, Layout layout)
	{
		if (!((Object)(object)container == (Object)null))
		{
			string text = PrefabName(container);
			if (layout.IsVanilla)
			{
				Plugin.Log.LogDebug((object)$"Opened {text} ({width}x{height}): left as is");
				return;
			}
			Plugin.Log.LogDebug((object)($"Opened {text} ({width}x{height}): showing as {layout.Columns}x{layout.Rows} " + $"at {layout.Scale:P0} size (view {viewWidth:F0}x{viewHeight:F0}, slot spacing {space:F0})"));
		}
	}
}
[BepInPlugin("falconnn.NoScrollWardrobes", "No Scroll Wardrobes", "0.2.0")]
public class Plugin : BaseUnityPlugin
{
	public const string Guid = "falconnn.NoScrollWardrobes";

	public const string Name = "No Scroll Wardrobes";

	public const string Version = "0.2.0";

	private const string DefaultContainers = "piece_chest_warderobe,piece_chest_grausten";

	private const string OldDefaultContainers = "piece_chest_warderobe";

	internal static ManualLogSource Log;

	internal static ConfigEntry<string> Containers;

	internal static ConfigEntry<bool> Graves;

	internal static HashSet<string> ContainerNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private Harmony _harmony;

	private void Awake()
	{
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Containers = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Containers", "piece_chest_warderobe,piece_chest_grausten", "Prefab names of containers to show in a grid that fits the panel instead of with a scrollbar, separated by commas. Use * to apply it to every container that would otherwise need a scrollbar. Only the on-screen layout changes; the stored items and their slots are untouched.");
		if (Containers.Value == "piece_chest_warderobe")
		{
			Containers.Value = "piece_chest_warderobe,piece_chest_grausten";
		}
		Graves = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Graves", true, "Also show graves without a scrollbar when they have more than 4 rows, which happens once a player has bought extra inventory rows.");
		ParseContainers();
		Containers.SettingChanged += delegate
		{
			ParseContainers();
		};
		_harmony = new Harmony("falconnn.NoScrollWardrobes");
		_harmony.PatchAll(typeof(Plugin).Assembly);
	}

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

	private static void ParseContainers()
	{
		ContainerNames.Clear();
		string[] array = Containers.Value.Split(',');
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i].Trim();
			if (text.Length > 0)
			{
				ContainerNames.Add(text);
			}
		}
	}
}