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 placedKeys = new HashSet(); private readonly HashSet activeKeys = new HashSet(); private readonly HashSet inactiveKeys = new HashSet(); internal static ComfortSnapshot Empty { get; } = new ComfortSnapshot(); internal int Total { get; private set; } internal bool InShelter { get; private set; } internal Dictionary GroupMax { get; } = new Dictionary(); 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 list = new List(); 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 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 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 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 list = new List(); 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 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 buildPieces = localPlayer.GetBuildPieces(); List 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 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 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 list = new List(); 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() : CreateBadge(iconGo, font, fontMaterial)); if (!((Object)(object)val2 == (Object)null)) { ((Component)val2).gameObject.SetActive(true); TextMeshProUGUI componentInChildren = ((Component)val2).GetComponentInChildren(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 list = PieceDiscovery.AllComfort(localPlayer); List list2 = new List(); HashSet hashSet = new HashSet(); 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'); 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(""); } } 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(); 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(); ((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(); 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().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().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(); ((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(); 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 Enabled; internal static ConfigEntry DebugLogging; internal static ConfigEntry ShowValueBadge; internal static ConfigEntry BadgeUpgradesOnly; internal static ConfigEntry ShowGroupCatalog; internal static ConfigEntry Policy; internal static ConfigEntry RequireMaterials; internal static void Bind(ConfigFile config) { Enabled = config.Bind("General", "Enabled", true, "Enable ComfortMe. When false, no Harmony patches run."); DebugLogging = config.Bind("General", "DebugLogging", false, "Log snapshot and classifier details to BepInEx."); ShowValueBadge = config.Bind("Hud", "ShowValueBadge", true, "Show a compact +N chip on every comfort hammer icon, colored vs this room."); BadgeUpgradesOnly = config.Bind("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("Hud", "ShowGroupCatalog", true, "When a comfort piece is selected, show that group's discovered pieces vs this room."); Policy = config.Bind("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("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(); } } }