Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ComfortMe v0.1.0
ComfortMe.dll
Decompiled 6 hours agousing 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(); } } }