Decompiled source of ComfortMe v0.1.0

ComfortMe.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ComfortMe")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Hammer helper that marks comfort pieces which would raise the room you are standing in.")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+5b55e04b3bdc2837625cb068bd84f3d8c46c4573")]
[assembly: AssemblyProduct("ComfortMe")]
[assembly: AssemblyTitle("ComfortMe")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ComfortMe
{
	[BepInPlugin("hardwire99.comfortme", "ComfortMe", "0.1.0")]
	public sealed class ComfortMePlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			if (!ModConfig.Enabled.Value)
			{
				Log.LogInfo((object)"ComfortMe 0.1.0 is disabled in config.");
				return;
			}
			harmony = new Harmony("hardwire99.comfortme");
			try
			{
				harmony.PatchAll(typeof(ComfortMePlugin).Assembly);
				Log.LogInfo((object)$"Harmony applied {harmony.GetPatchedMethods().Count()} patch(es).");
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Harmony PatchAll failed: {arg}");
			}
			Log.LogInfo((object)("ComfortMe 0.1.0 loaded (chips-all, dll " + GetDllTimestamp() + ")."));
		}

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

		private static string GetDllTimestamp()
		{
			string location = Assembly.GetExecutingAssembly().Location;
			if (!File.Exists(location))
			{
				return "unknown";
			}
			return File.GetLastWriteTime(location).ToString("yyyy-MM-dd HH:mm:ss");
		}
	}
	internal enum ComfortVerdict
	{
		Skip,
		NewGroup,
		Upgrade,
		Redundant,
		Unlit,
		Downgrade
	}
	internal readonly struct ComfortClassification
	{
		internal ComfortVerdict Verdict { get; }

		internal ComfortGroup Group { get; }

		internal int Current { get; }

		internal int Candidate { get; }

		internal int Delta { get; }

		internal bool IsUpgrade
		{
			get
			{
				if (Verdict != ComfortVerdict.Upgrade)
				{
					return Verdict == ComfortVerdict.NewGroup;
				}
				return true;
			}
		}

		internal ComfortClassification(ComfortVerdict verdict, ComfortGroup group, int current, int candidate)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			Verdict = verdict;
			Group = group;
			Current = current;
			Candidate = candidate;
			Delta = candidate - current;
		}
	}
	internal sealed class ComfortSnapshot
	{
		private const float CacheSeconds = 0.2f;

		private const float CacheMoveSqr = 0.0625f;

		private static ComfortSnapshot cached;

		private static Vector3 cachedPos;

		private static float cachedTime = -999f;

		private static bool cachedShelter;

		private readonly HashSet<string> placedKeys = new HashSet<string>();

		private readonly HashSet<string> activeKeys = new HashSet<string>();

		private readonly HashSet<string> inactiveKeys = new HashSet<string>();

		internal static ComfortSnapshot Empty { get; } = new ComfortSnapshot();

		internal int Total { get; private set; }

		internal bool InShelter { get; private set; }

		internal Dictionary<ComfortGroup, int> GroupMax { get; } = new Dictionary<ComfortGroup, int>();

		internal static ComfortSnapshot Capture(Player player)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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)
			if ((Object)(object)player == (Object)null)
			{
				return Empty;
			}
			Vector3 position = ((Component)player).transform.position;
			bool flag = player.InShelter();
			float time = Time.time;
			if (cached != null && time - cachedTime < 0.2f)
			{
				Vector3 val = position - cachedPos;
				if (((Vector3)(ref val)).sqrMagnitude < 0.0625f && flag == cachedShelter)
				{
					return cached;
				}
			}
			ComfortSnapshot comfortSnapshot = new ComfortSnapshot
			{
				InShelter = flag,
				Total = SE_Rested.CalculateComfortLevel(player)
			};
			List<Piece> list = new List<Piece>();
			Piece.GetAllComfortPiecesInRadius(position, 10f, list);
			for (int i = 0; i < list.Count; i++)
			{
				Piece val2 = list[i];
				if ((Object)(object)val2 == (Object)null || val2.m_comfort <= 0)
				{
					continue;
				}
				AddIdentity(comfortSnapshot.placedKeys, val2);
				int comfort = val2.GetComfort();
				if (comfort > 0)
				{
					AddIdentity(comfortSnapshot.activeKeys, val2);
					ComfortGroup comfortGroup = val2.m_comfortGroup;
					if ((int)comfortGroup != 0 && (!comfortSnapshot.GroupMax.TryGetValue(comfortGroup, out var value) || comfort > value))
					{
						comfortSnapshot.GroupMax[comfortGroup] = comfort;
					}
				}
				else
				{
					AddIdentity(comfortSnapshot.inactiveKeys, val2);
				}
			}
			cached = comfortSnapshot;
			cachedPos = position;
			cachedTime = time;
			cachedShelter = flag;
			return comfortSnapshot;
		}

		internal int CurrentFor(ComfortGroup group)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)group == 0)
			{
				return 0;
			}
			if (!GroupMax.TryGetValue(group, out var value))
			{
				return 0;
			}
			return value;
		}

		internal bool HasPlaced(Piece piece)
		{
			return Matches(placedKeys, piece);
		}

		internal bool HasActive(Piece piece)
		{
			return Matches(activeKeys, piece);
		}

		internal bool IsInactivePresent(Piece piece)
		{
			if (Matches(inactiveKeys, piece))
			{
				return !Matches(activeKeys, piece);
			}
			return false;
		}

		private static void AddIdentity(HashSet<string> keys, Piece piece)
		{
			if (!string.IsNullOrEmpty(piece.m_name))
			{
				keys.Add(piece.m_name);
			}
			string text = PrefabName(piece);
			if (!string.IsNullOrEmpty(text))
			{
				keys.Add(text);
			}
		}

		private static bool Matches(HashSet<string> keys, Piece piece)
		{
			if ((Object)(object)piece == (Object)null || keys.Count == 0)
			{
				return false;
			}
			if (!string.IsNullOrEmpty(piece.m_name) && keys.Contains(piece.m_name))
			{
				return true;
			}
			string text = PrefabName(piece);
			if (!string.IsNullOrEmpty(text))
			{
				return keys.Contains(text);
			}
			return false;
		}

		private static string PrefabName(Piece piece)
		{
			if (!((Object)(object)((Component)piece).gameObject != (Object)null))
			{
				return string.Empty;
			}
			return Utils.GetPrefabName(((Component)piece).gameObject);
		}
	}
	internal readonly struct DiscoveredPiece
	{
		internal Piece Piece { get; }

		internal PieceCategory Category { get; }

		internal DiscoveredPiece(Piece piece, PieceCategory category)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			Piece = piece;
			Category = category;
		}
	}
	internal static class PieceDiscovery
	{
		private static readonly FieldInfo BuildPiecesField = AccessTools.Field(typeof(Player), "m_buildPieces");

		private static readonly FieldInfo AvailableField = AccessTools.Field(typeof(PieceTable), "m_availablePieces");

		internal static PieceTable GetTable(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				object? obj = BuildPiecesField?.GetValue(player);
				return (PieceTable)((obj is PieceTable) ? obj : null);
			}
			return null;
		}

		internal static List<DiscoveredPiece> AllComfort(Player player)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			List<DiscoveredPiece> list = new List<DiscoveredPiece>();
			PieceTable table = GetTable(player);
			if (!(AvailableField?.GetValue(table) is IList list2))
			{
				return list;
			}
			for (int i = 0; i < list2.Count; i++)
			{
				if (!(list2[i] is IList list3))
				{
					continue;
				}
				PieceCategory category = (PieceCategory)i;
				for (int j = 0; j < list3.Count; j++)
				{
					object? obj = list3[j];
					Piece val = (Piece)((obj is Piece) ? obj : null);
					if (val != null && val.m_comfort > 0)
					{
						list.Add(new DiscoveredPiece(val, category));
					}
				}
			}
			return list;
		}

		internal static int BestUpgradeComfort(Player player, ComfortGroup group, ComfortSnapshot snapshot)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			List<DiscoveredPiece> list = AllComfort(player);
			for (int i = 0; i < list.Count; i++)
			{
				Piece piece = list[i].Piece;
				if (piece.m_comfortGroup == group && UpgradeClassifier.Classify(piece, snapshot).IsUpgrade && piece.m_comfort > num)
				{
					num = piece.m_comfort;
				}
			}
			return num;
		}

		internal static string CategoryLabel(PieceTable table, PieceCategory category)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)table != (Object)null && table.m_categories != null && table.m_categoryLabels != null)
			{
				int num = table.m_categories.IndexOf(category);
				if (num >= 0 && num < table.m_categoryLabels.Count)
				{
					string text = table.m_categoryLabels[num];
					if (!string.IsNullOrEmpty(text) && Localization.instance != null)
					{
						return Localization.instance.Localize(text);
					}
					if (!string.IsNullOrEmpty(text))
					{
						return text;
					}
				}
			}
			return CategoryFallback(category);
		}

		internal static string LocalName(Piece piece)
		{
			if ((Object)(object)piece == (Object)null || string.IsNullOrEmpty(piece.m_name))
			{
				return string.Empty;
			}
			if (Localization.instance == null)
			{
				return piece.m_name;
			}
			return Localization.instance.Localize(piece.m_name);
		}

		internal unsafe static string GroupLabel(ComfortGroup group)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected I4, but got Unknown
			return (int)group switch
			{
				1 => "Fire", 
				2 => "Bed", 
				3 => "Banner", 
				4 => "Seating", 
				5 => "Table", 
				6 => "Carpet", 
				0 => "Unique", 
				_ => ((object)(*(ComfortGroup*)(&group))/*cast due to .constrained prefix*/).ToString(), 
			};
		}

		private unsafe static string CategoryFallback(PieceCategory category)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected I4, but got Unknown
			return (int)category switch
			{
				0 => "Misc", 
				1 => "Crafting", 
				2 => "Building", 
				3 => "Stonecutter", 
				4 => "Furniture", 
				_ => ((object)(*(PieceCategory*)(&category))/*cast due to .constrained prefix*/).ToString(), 
			};
		}
	}
	internal static class UpgradeClassifier
	{
		internal static ComfortClassification Classify(Piece piece, ComfortSnapshot snapshot)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)piece == (Object)null || snapshot == null || piece.m_comfort <= 0)
			{
				return new ComfortClassification(ComfortVerdict.Skip, (ComfortGroup)0, 0, 0);
			}
			ComfortGroup comfortGroup = piece.m_comfortGroup;
			int comfort = piece.m_comfort;
			if ((int)comfortGroup == 0)
			{
				if (snapshot.HasActive(piece))
				{
					return new ComfortClassification(ComfortVerdict.Redundant, comfortGroup, comfort, comfort);
				}
				if (snapshot.HasPlaced(piece))
				{
					return new ComfortClassification(ComfortVerdict.Unlit, comfortGroup, 0, comfort);
				}
				return new ComfortClassification(ComfortVerdict.NewGroup, comfortGroup, 0, comfort);
			}
			int num = snapshot.CurrentFor(comfortGroup);
			if (comfort > num)
			{
				if (snapshot.IsInactivePresent(piece))
				{
					return new ComfortClassification(ComfortVerdict.Unlit, comfortGroup, num, comfort);
				}
				return new ComfortClassification((num == 0) ? ComfortVerdict.NewGroup : ComfortVerdict.Upgrade, comfortGroup, num, comfort);
			}
			if (comfort == num)
			{
				return new ComfortClassification(ComfortVerdict.Redundant, comfortGroup, num, comfort);
			}
			return new ComfortClassification(ComfortVerdict.Downgrade, comfortGroup, num, comfort);
		}

		internal static bool ShouldBadge(Player player, Piece piece, ComfortClassification classification, ComfortSnapshot snapshot)
		{
			//IL_004d: 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)
			if (!classification.IsUpgrade)
			{
				return false;
			}
			if (ModConfig.RequireMaterials.Value && (Object)(object)player != (Object)null && !player.HaveRequirements(piece, (RequirementMode)0))
			{
				return false;
			}
			HighlightPolicy value = ModConfig.Policy.Value;
			if (value == HighlightPolicy.UpgradeOnly && classification.Verdict == ComfortVerdict.NewGroup)
			{
				return false;
			}
			if (value == HighlightPolicy.BestAvailable && (int)classification.Group != 0 && (Object)(object)player != (Object)null)
			{
				int num = PieceDiscovery.BestUpgradeComfort(player, classification.Group, snapshot);
				if (num > 0)
				{
					return piece.m_comfort >= num;
				}
				return false;
			}
			return true;
		}
	}
	internal static class BuildHudBadge
	{
		private const string BadgeName = "ComfortMeBadge";

		private static readonly Color ChipBackground = new Color(0.05f, 0.07f, 0.06f, 0.88f);

		private static readonly Color UpgradeGreen = new Color(0.35f, 0.85f, 0.55f, 1f);

		private static readonly Color EqualGrey = new Color(0.72f, 0.72f, 0.72f, 1f);

		private static readonly Color LowerRed = new Color(0.85f, 0.36f, 0.36f, 1f);

		private static readonly FieldInfo PieceIconsField = AccessTools.Field(typeof(Hud), "m_pieceIcons");

		private static readonly FieldInfo IconGoField = AccessTools.Field(AccessTools.Inner(typeof(Hud), "PieceIconData"), "m_go");

		internal static void Clear()
		{
		}

		internal static void Refresh(Hud hud, ComfortSnapshot snapshot)
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)hud == (Object)null || snapshot == null || !ModConfig.ShowValueBadge.Value || (Object)(object)hud.m_buildHud == (Object)null || !hud.m_buildHud.activeInHierarchy)
			{
				HideAll(hud);
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				HideAll(hud);
				return;
			}
			List<Piece> buildPieces = localPlayer.GetBuildPieces();
			List<GameObject> iconObjects = GetIconObjects(hud);
			if (buildPieces == null || iconObjects.Count == 0)
			{
				return;
			}
			TMP_FontAsset font = HudUi.FontFrom(hud);
			Material fontMaterial = HudUi.FontMaterialFrom(hud);
			int num = Mathf.Min(buildPieces.Count, iconObjects.Count);
			for (int i = 0; i < iconObjects.Count; i++)
			{
				GameObject val = iconObjects[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				if (i >= num)
				{
					SetBadge(val, font, fontMaterial, visible: false, string.Empty, UpgradeGreen);
					continue;
				}
				Piece val2 = buildPieces[i];
				ComfortClassification classification = UpgradeClassifier.Classify(val2, snapshot);
				bool flag;
				Color color;
				if (ModConfig.BadgeUpgradesOnly.Value)
				{
					flag = UpgradeClassifier.ShouldBadge(localPlayer, val2, classification, snapshot);
					color = UpgradeGreen;
				}
				else
				{
					flag = classification.Verdict != ComfortVerdict.Skip;
					if (ModConfig.RequireMaterials.Value && !localPlayer.HaveRequirements(val2, (RequirementMode)0))
					{
						flag = false;
					}
					if (ModConfig.Policy.Value == HighlightPolicy.UpgradeOnly && classification.Verdict == ComfortVerdict.NewGroup)
					{
						flag = false;
					}
					color = ColorFor(classification.Verdict);
				}
				string label = (flag ? ("+" + val2.m_comfort) : string.Empty);
				SetBadge(val, font, fontMaterial, flag, label, color);
			}
		}

		private static Color ColorFor(ComfortVerdict verdict)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			switch (verdict)
			{
			case ComfortVerdict.NewGroup:
			case ComfortVerdict.Upgrade:
				return UpgradeGreen;
			case ComfortVerdict.Downgrade:
				return LowerRed;
			default:
				return EqualGrey;
			}
		}

		private static void HideAll(Hud hud)
		{
			List<GameObject> iconObjects = GetIconObjects(hud);
			for (int i = 0; i < iconObjects.Count; i++)
			{
				GameObject val = iconObjects[i];
				if (!((Object)(object)val == (Object)null))
				{
					Transform val2 = val.transform.Find("ComfortMeBadge");
					if ((Object)(object)val2 != (Object)null)
					{
						((Component)val2).gameObject.SetActive(false);
					}
				}
			}
		}

		private static List<GameObject> GetIconObjects(Hud hud)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			List<GameObject> list = new List<GameObject>();
			if (PieceIconsField?.GetValue(hud) is IList list2 && IconGoField != null)
			{
				for (int i = 0; i < list2.Count; i++)
				{
					object? value = IconGoField.GetValue(list2[i]);
					GameObject val = (GameObject)((value is GameObject) ? value : null);
					if (val != null)
					{
						list.Add(val);
					}
				}
				return list;
			}
			if ((Object)(object)hud != (Object)null && (Object)(object)hud.m_pieceListRoot != (Object)null)
			{
				foreach (Transform item in (Transform)hud.m_pieceListRoot)
				{
					Transform val2 = item;
					if ((Object)(object)val2 != (Object)null && ((Object)val2).name != "ComfortMeBadge")
					{
						list.Add(((Component)val2).gameObject);
					}
				}
			}
			return list;
		}

		private static void SetBadge(GameObject iconGo, TMP_FontAsset font, Material fontMaterial, bool visible, string label, Color color)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			Transform val = iconGo.transform.Find("ComfortMeBadge");
			if (!visible)
			{
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).gameObject.SetActive(false);
				}
				return;
			}
			Image val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Image>() : CreateBadge(iconGo, font, fontMaterial));
			if (!((Object)(object)val2 == (Object)null))
			{
				((Component)val2).gameObject.SetActive(true);
				TextMeshProUGUI componentInChildren = ((Component)val2).GetComponentInChildren<TextMeshProUGUI>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					((TMP_Text)componentInChildren).text = label;
					((Graphic)componentInChildren).color = color;
				}
			}
		}

		private static Image CreateBadge(GameObject iconGo, TMP_FontAsset font, Material fontMaterial)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			Image obj = HudUi.CreatePanel(iconGo.transform, "ComfortMeBadge", ChipBackground);
			RectTransform rectTransform = ((Graphic)obj).rectTransform;
			rectTransform.anchorMin = new Vector2(1f, 1f);
			rectTransform.anchorMax = new Vector2(1f, 1f);
			rectTransform.pivot = new Vector2(1f, 1f);
			rectTransform.sizeDelta = new Vector2(28f, 16f);
			rectTransform.anchoredPosition = new Vector2(-2f, -2f);
			((Transform)rectTransform).SetAsLastSibling();
			TextMeshProUGUI obj2 = HudUi.CreateText(((Component)obj).transform, "Text", font, fontMaterial, 11f);
			((TMP_Text)obj2).alignment = (TextAlignmentOptions)514;
			((Graphic)obj2).color = UpgradeGreen;
			RectTransform rectTransform2 = ((TMP_Text)obj2).rectTransform;
			rectTransform2.anchorMin = Vector2.zero;
			rectTransform2.anchorMax = Vector2.one;
			rectTransform2.offsetMin = Vector2.zero;
			rectTransform2.offsetMax = Vector2.zero;
			return obj;
		}
	}
	internal static class GroupCatalogPanel
	{
		private readonly struct CatalogRow
		{
			internal string Name { get; }

			internal int Comfort { get; }

			internal ComfortVerdict Verdict { get; }

			internal string Tab { get; }

			internal CatalogRow(string name, int comfort, ComfortVerdict verdict, string tab)
			{
				Name = name;
				Comfort = comfort;
				Verdict = verdict;
				Tab = tab;
			}
		}

		private const string PanelName = "ComfortMeCatalog";

		private static readonly Color PanelBackground = new Color(0.04f, 0.05f, 0.05f, 0.86f);

		private static readonly Color HeaderColor = new Color(0.92f, 0.93f, 0.9f, 1f);

		private static readonly Color UpgradeGreen = new Color(0.35f, 0.85f, 0.55f, 1f);

		private static readonly Color EqualGrey = new Color(0.72f, 0.72f, 0.72f, 1f);

		private static readonly Color LowerRed = new Color(0.85f, 0.36f, 0.36f, 1f);

		private static readonly Color UnlitAmber = new Color(0.95f, 0.72f, 0.28f, 1f);

		private static Image panel;

		private static TextMeshProUGUI header;

		private static TextMeshProUGUI body;

		private static string lastText;

		internal static void Hide()
		{
			if ((Object)(object)panel != (Object)null)
			{
				((Component)panel).gameObject.SetActive(false);
			}
			lastText = null;
		}

		internal static void Refresh(Hud hud, Piece selected, ComfortSnapshot snapshot)
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)hud == (Object)null || snapshot == null || !ModConfig.Enabled.Value || !Hud.IsPieceSelectionVisible())
			{
				Hide();
				return;
			}
			EnsurePanel(hud);
			if ((Object)(object)panel == (Object)null)
			{
				return;
			}
			((Component)panel).gameObject.SetActive(true);
			StringBuilder stringBuilder = new StringBuilder(256);
			stringBuilder.Append("This room: ").Append(snapshot.Total);
			if (!snapshot.InShelter)
			{
				stringBuilder.Append("  (unsheltered)");
			}
			if (ModConfig.ShowGroupCatalog.Value && (Object)(object)selected != (Object)null && selected.m_comfort > 0)
			{
				ComfortClassification comfortClassification = UpgradeClassifier.Classify(selected, snapshot);
				stringBuilder.Append('\n');
				stringBuilder.Append(PieceDiscovery.GroupLabel(selected.m_comfortGroup));
				if ((int)selected.m_comfortGroup == 0)
				{
					if (snapshot.HasActive(selected))
					{
						stringBuilder.Append(" here: already placed");
					}
					else if (snapshot.HasPlaced(selected))
					{
						stringBuilder.Append(" here: unlit");
					}
					else
					{
						stringBuilder.Append(" here: missing");
					}
				}
				else
				{
					stringBuilder.Append(" here: +").Append(comfortClassification.Current);
				}
				AppendGroupRows(stringBuilder, selected, snapshot);
			}
			string text = stringBuilder.ToString();
			if (!(text == lastText))
			{
				lastText = text;
				int num = text.IndexOf('\n');
				if ((Object)(object)header != (Object)null)
				{
					((TMP_Text)header).text = ((num >= 0) ? text.Substring(0, num) : text);
				}
				if ((Object)(object)body != (Object)null)
				{
					((TMP_Text)body).text = ((num >= 0) ? text.Substring(num + 1) : string.Empty);
					((Component)body).gameObject.SetActive(((TMP_Text)body).text.Length > 0);
				}
			}
		}

		private static void AppendGroupRows(StringBuilder builder, Piece selected, ComfortSnapshot snapshot)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			PieceTable table = PieceDiscovery.GetTable(localPlayer);
			List<DiscoveredPiece> list = PieceDiscovery.AllComfort(localPlayer);
			List<CatalogRow> list2 = new List<CatalogRow>();
			HashSet<string> hashSet = new HashSet<string>();
			for (int i = 0; i < list.Count; i++)
			{
				Piece piece = list[i].Piece;
				if (piece.m_comfortGroup == selected.m_comfortGroup && hashSet.Add(piece.m_name))
				{
					ComfortClassification comfortClassification = UpgradeClassifier.Classify(piece, snapshot);
					list2.Add(new CatalogRow(PieceDiscovery.LocalName(piece), piece.m_comfort, comfortClassification.Verdict, (list[i].Category != selected.m_category) ? PieceDiscovery.CategoryLabel(table, list[i].Category) : null));
				}
			}
			list2.Sort(CompareRows);
			for (int j = 0; j < list2.Count; j++)
			{
				CatalogRow catalogRow = list2[j];
				Color color = ColorFor(catalogRow.Verdict);
				builder.Append("\n<color=#").Append(HudUi.Hex(color)).Append('>');
				builder.Append(catalogRow.Name).Append("  +").Append(catalogRow.Comfort);
				if (catalogRow.Verdict == ComfortVerdict.Unlit)
				{
					builder.Append("  (unlit)");
				}
				if (!string.IsNullOrEmpty(catalogRow.Tab))
				{
					builder.Append("  (").Append(catalogRow.Tab).Append(')');
				}
				builder.Append("</color>");
			}
		}

		private static int CompareRows(CatalogRow a, CatalogRow b)
		{
			int num = a.Comfort.CompareTo(b.Comfort);
			if (num == 0)
			{
				return string.CompareOrdinal(a.Name, b.Name);
			}
			return num;
		}

		private static Color ColorFor(ComfortVerdict verdict)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			switch (verdict)
			{
			case ComfortVerdict.NewGroup:
			case ComfortVerdict.Upgrade:
				return UpgradeGreen;
			case ComfortVerdict.Downgrade:
				return LowerRed;
			case ComfortVerdict.Unlit:
				return UnlitAmber;
			default:
				return EqualGrey;
			}
		}

		private static void EnsurePanel(Hud hud)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Expected O, but got Unknown
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)panel != (Object)null && !Object.op_Implicit((Object)(object)panel))
			{
				panel = null;
				header = null;
				body = null;
				lastText = null;
			}
			Transform val = ResolveParent(hud);
			if ((Object)(object)panel != (Object)null && (Object)(object)val != (Object)null && (Object)(object)((Component)panel).transform.parent != (Object)(object)val)
			{
				Object.Destroy((Object)(object)((Component)panel).gameObject);
				panel = null;
				header = null;
				body = null;
				lastText = null;
			}
			if (!((Object)(object)panel != (Object)null))
			{
				TMP_FontAsset val2 = HudUi.FontFrom(hud);
				Material fontMaterial = HudUi.FontMaterialFrom(hud);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null))
				{
					panel = HudUi.CreatePanel(val, "ComfortMeCatalog", PanelBackground);
					Canvas obj = ((Component)panel).gameObject.AddComponent<Canvas>();
					obj.overrideSorting = true;
					obj.sortingOrder = 31000;
					RectTransform rectTransform = ((Graphic)panel).rectTransform;
					rectTransform.anchorMin = new Vector2(1f, 0f);
					rectTransform.anchorMax = new Vector2(1f, 0f);
					rectTransform.pivot = new Vector2(1f, 1f);
					rectTransform.anchoredPosition = new Vector2(-8f, -6f);
					rectTransform.sizeDelta = new Vector2(280f, 0f);
					((Transform)rectTransform).SetAsLastSibling();
					VerticalLayoutGroup obj2 = ((Component)panel).gameObject.AddComponent<VerticalLayoutGroup>();
					((LayoutGroup)obj2).padding = new RectOffset(10, 10, 8, 8);
					((HorizontalOrVerticalLayoutGroup)obj2).spacing = 4f;
					((LayoutGroup)obj2).childAlignment = (TextAnchor)0;
					((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
					((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
					((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false;
					((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true;
					ContentSizeFitter obj3 = ((Component)panel).gameObject.AddComponent<ContentSizeFitter>();
					obj3.horizontalFit = (FitMode)0;
					obj3.verticalFit = (FitMode)2;
					header = HudUi.CreateText(((Component)panel).transform, "Header", val2, fontMaterial, 16f);
					((TMP_Text)header).alignment = (TextAlignmentOptions)257;
					((Graphic)header).color = HeaderColor;
					((TMP_Text)header).textWrappingMode = (TextWrappingModes)1;
					((Component)header).gameObject.AddComponent<LayoutElement>().minWidth = 220f;
					body = HudUi.CreateText(((Component)panel).transform, "Body", val2, fontMaterial, 14f);
					((TMP_Text)body).alignment = (TextAlignmentOptions)257;
					((Graphic)body).color = HeaderColor;
					((TMP_Text)body).textWrappingMode = (TextWrappingModes)1;
					((Component)body).gameObject.AddComponent<LayoutElement>().minWidth = 220f;
				}
			}
		}

		private static Transform ResolveParent(Hud hud)
		{
			if ((Object)(object)hud.m_pieceSelectionWindow != (Object)null)
			{
				return hud.m_pieceSelectionWindow.transform;
			}
			if (!((Object)(object)hud.m_buildHud != (Object)null))
			{
				return null;
			}
			return hud.m_buildHud.transform;
		}
	}
	internal static class HudUi
	{
		private static Sprite whiteSprite;

		internal static Sprite WhiteSprite
		{
			get
			{
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)whiteSprite == (Object)null)
				{
					Texture2D whiteTexture = Texture2D.whiteTexture;
					whiteSprite = Sprite.Create(whiteTexture, new Rect(0f, 0f, (float)((Texture)whiteTexture).width, (float)((Texture)whiteTexture).height), new Vector2(0.5f, 0.5f), 100f);
				}
				return whiteSprite;
			}
		}

		internal static TMP_FontAsset FontFrom(Hud hud)
		{
			if (!((Object)(object)hud != (Object)null) || !((Object)(object)hud.m_buildSelection != (Object)null))
			{
				return null;
			}
			return hud.m_buildSelection.font;
		}

		internal static Material FontMaterialFrom(Hud hud)
		{
			if (!((Object)(object)hud != (Object)null) || !((Object)(object)hud.m_buildSelection != (Object)null))
			{
				return null;
			}
			return hud.m_buildSelection.fontSharedMaterial;
		}

		internal static TextMeshProUGUI CreateText(Transform parent, string name, TMP_FontAsset font, Material fontMaterial, float size)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) })
			{
				layer = ((Component)parent).gameObject.layer
			};
			val.transform.SetParent(parent, false);
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val2).font = font;
			if ((Object)(object)fontMaterial != (Object)null)
			{
				((TMP_Text)val2).fontSharedMaterial = fontMaterial;
			}
			((TMP_Text)val2).fontSize = size;
			((Graphic)val2).raycastTarget = false;
			((TMP_Text)val2).overflowMode = (TextOverflowModes)0;
			((TMP_Text)val2).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)val2).richText = true;
			return val2;
		}

		internal static Image CreatePanel(Transform parent, string name, Color color)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			})
			{
				layer = ((Component)parent).gameObject.layer
			};
			val.transform.SetParent(parent, false);
			Image component = val.GetComponent<Image>();
			component.sprite = WhiteSprite;
			((Graphic)component).color = color;
			((Graphic)component).raycastTarget = false;
			return component;
		}

		internal static string Hex(Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return ColorUtility.ToHtmlStringRGB(color);
		}
	}
	internal enum HighlightPolicy
	{
		AnyIncrease,
		BestAvailable,
		UpgradeOnly
	}
	internal static class ModConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ConfigEntry<bool> ShowValueBadge;

		internal static ConfigEntry<bool> BadgeUpgradesOnly;

		internal static ConfigEntry<bool> ShowGroupCatalog;

		internal static ConfigEntry<HighlightPolicy> Policy;

		internal static ConfigEntry<bool> RequireMaterials;

		internal static void Bind(ConfigFile config)
		{
			Enabled = config.Bind<bool>("General", "Enabled", true, "Enable ComfortMe. When false, no Harmony patches run.");
			DebugLogging = config.Bind<bool>("General", "DebugLogging", false, "Log snapshot and classifier details to BepInEx.");
			ShowValueBadge = config.Bind<bool>("Hud", "ShowValueBadge", true, "Show a compact +N chip on every comfort hammer icon, colored vs this room.");
			BadgeUpgradesOnly = config.Bind<bool>("Hud", "BadgeUpgradesOnly", false, "When true, only green upgrade chips appear. Default shows +N on every comfort piece: green raise, grey equal/unlit, red lower.");
			ShowGroupCatalog = config.Bind<bool>("Hud", "ShowGroupCatalog", true, "When a comfort piece is selected, show that group's discovered pieces vs this room.");
			Policy = config.Bind<HighlightPolicy>("Hud", "HighlightPolicy", HighlightPolicy.AnyIncrease, "AnyIncrease: badge every piece that would raise comfort. BestAvailable: only the best discovered piece in that group. UpgradeOnly: in-group upgrades, not missing groups.");
			RequireMaterials = config.Bind<bool>("Hud", "RequireMaterials", false, "When true, only badge pieces you can currently place. Default leaves greyed icons badgeable as a shopping hint.");
		}

		internal static void LogDebug(string message)
		{
			if (DebugLogging.Value)
			{
				ManualLogSource log = ComfortMePlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)message);
				}
			}
		}
	}
	internal static class ModConstants
	{
		public const string ModGuid = "hardwire99.comfortme";

		public const string ModName = "ComfortMe";

		public const string ModVersion = "0.1.0";

		public const string BuildLabel = "chips-all";

		public const float ComfortRadius = 10f;
	}
}
namespace ComfortMe.Patches
{
	[HarmonyPatch(typeof(Hud), "UpdatePieceList")]
	internal static class HudUpdatePieceListPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Hud __instance, Player player)
		{
			if (!ModConfig.Enabled.Value)
			{
				return;
			}
			try
			{
				ComfortSnapshot snapshot = ComfortSnapshot.Capture(player);
				BuildHudBadge.Refresh(__instance, snapshot);
			}
			catch (Exception arg)
			{
				ManualLogSource log = ComfortMePlugin.Log;
				if (log != null)
				{
					log.LogError((object)$"UpdatePieceList HUD failed: {arg}");
				}
			}
		}
	}
	[HarmonyPatch(typeof(Hud), "SetupPieceInfo")]
	internal static class HudSetupPieceInfoPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Hud __instance, Piece piece)
		{
			if (!ModConfig.Enabled.Value)
			{
				return;
			}
			try
			{
				ComfortSnapshot snapshot = ComfortSnapshot.Capture(Player.m_localPlayer);
				GroupCatalogPanel.Refresh(__instance, piece, snapshot);
			}
			catch (Exception arg)
			{
				ManualLogSource log = ComfortMePlugin.Log;
				if (log != null)
				{
					log.LogError((object)$"SetupPieceInfo HUD failed: {arg}");
				}
			}
		}
	}
	[HarmonyPatch(typeof(Hud), "OnDestroy")]
	internal static class HudOnDestroyPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			BuildHudBadge.Clear();
			GroupCatalogPanel.Hide();
		}
	}
}