From 89fc29d94cf2ac4b42ed9cce3e5ca45db2048003 Mon Sep 17 00:00:00 2001 From: mibac138 <5672750+mibac138@users.noreply.github.com> Date: Wed, 22 Apr 2026 02:09:51 +0200 Subject: [PATCH] Show mod compat scores in the main mod list dialog Shows XML mods as a 4 to save on the limited space and avoid needlessly complicating the logic --- Source/Client/ModCompatibilityManager.cs | 22 +++++ Source/Client/Windows/ModCompatWindow.cs | 102 ++++++++++++++++++----- 2 files changed, 103 insertions(+), 21 deletions(-) diff --git a/Source/Client/ModCompatibilityManager.cs b/Source/Client/ModCompatibilityManager.cs index e7c3d409b..fd6072463 100644 --- a/Source/Client/ModCompatibilityManager.cs +++ b/Source/Client/ModCompatibilityManager.cs @@ -10,6 +10,7 @@ using Multiplayer.Common; using RestSharp; using Steamworks; +using UnityEngine; using Verse; namespace Multiplayer.Client @@ -165,6 +166,9 @@ private static void SetupFrom(List mods) .ToDictionary(grouping => grouping.Key, grouping => grouping.First()); } + public static ModCompatibility? LookupByMod(ModMetaData meta) => + LookupByWorkshopId(meta.GetPublishedFileId()) ?? LookupByName(meta.Name); + public static ModCompatibility? LookupByWorkshopId(PublishedFileId_t workshopId) => LookupByWorkshopId(workshopId.m_PublishedFileId); @@ -188,5 +192,23 @@ public class ModCompatibility public string name { get; set; } public long workshopId { get; set; } public string notes { get; set; } = ""; + + public static Color ScoreColor(int score) => score switch + { + 1 => ColorLibrary.Red, + 2 => ColorLibrary.Orange, + 3 => ColorLibrary.Yellow, + 4 => ColorLibrary.Green, + _ => ColorLibrary.Grey + }; + + public static string ScoreDescription(int score) => score switch + { + 1 => "MpModCompatScore1", + 2 => "MpModCompatScore2", + 3 => "MpModCompatScore3", + 4 => "MpModCompatScore4", + _ => "MpModCompatScoreUnk" + }; } } diff --git a/Source/Client/Windows/ModCompatWindow.cs b/Source/Client/Windows/ModCompatWindow.cs index 656aff6a2..0092cf25c 100644 --- a/Source/Client/Windows/ModCompatWindow.cs +++ b/Source/Client/Windows/ModCompatWindow.cs @@ -40,7 +40,7 @@ public ModCompatWindow(Window parent, bool popup, bool forceNameSort, Func modNameCache = new(); private Dictionary notesCache = new(); @@ -75,6 +76,12 @@ public override void SetInitialSizeAndPosition() const float ScrollbarWidth = 20f; const float ListInset = 15f; + public void ScrollToModName(string modName) + { + nameFieldStr = modName; + scrollToModName = true; + } + public override void DoWindowContents(Rect inRect) { if (modsHash != ModLister.InstalledModsListHash(true)) @@ -128,6 +135,11 @@ ref Multiplayer.settings.hideTranslationMods GUI.SetNextControlName("mod_search"); nameFieldStr = Widgets.TextField(nameField, nameFieldStr); nameFieldChanged = nameFieldStr != prevNameField; + if (scrollToModName) + { + nameFieldChanged = true; + scrollToModName = false; + } inRect.yMin += CheckboxesHeight + 10f; GUI.BeginGroup(inRect); @@ -249,7 +261,7 @@ private void DoHeaders(float width) // Notes header var notesHeader = headerRow.MaxX(headerRow.width - ScrollbarWidth); - Widgets.Label(notesHeader, $"MpModCompatHeaderNotes".Translate()); + Widgets.Label(notesHeader, "MpModCompatHeaderNotes".Translate()); Widgets.DrawHighlightIfMouseover(notesHeader); } @@ -275,23 +287,10 @@ private void DoModRow(ModMetaData mod, bool alt, Rect row) { bool xml = MultiplayerData.IsXmlMod(mod); - var scoreColor = xml ? ColorLibrary.Green : info?.status switch - { - 1 => ColorLibrary.Red, - 2 => ColorLibrary.Orange, - 3 => ColorLibrary.Yellow, - 4 => ColorLibrary.Green, - _ => ColorLibrary.Grey - }; - - var scoreDescKey = xml ? "MpModCompatXmlOnlyDesc" : info?.status switch - { - 1 => "MpModCompatScore1", - 2 => "MpModCompatScore2", - 3 => "MpModCompatScore3", - 4 => "MpModCompatScore4", - _ => "MpModCompatScoreUnk" - }; + var scoreColor = xml ? ColorLibrary.Green : ModCompatibility.ScoreColor(info?.status ?? 0); + + var scoreDescKey = + xml ? "MpModCompatXmlOnlyDesc" : ModCompatibility.ScoreDescription(info?.status ?? 0); var scoreText = xml ? "XML" @@ -368,8 +367,7 @@ private static ModCompatibility TryGetCompatInfo(ModMetaData mod) if (!Multiplayer.settings.showModCompatibility) return null; - return ModCompatibilityManager.LookupByWorkshopId(mod.publishedFileIdInt) ?? - ModCompatibilityManager.LookupByName(mod.Name); + return ModCompatibilityManager.LookupByMod(mod); } private static string SortChar(SortDirection dir) => dir switch @@ -402,6 +400,68 @@ static IEnumerable Transpiler(IEnumerable inst } } + [HarmonyPatch(typeof(Page_ModsConfig), nameof(Page_ModsConfig.DoModRow))] + static class PageModsConfigShowModCompat + { + static IEnumerable Transpiler(IEnumerable insts) + { + var labelMethod = + AccessTools.Method(typeof(Widgets), nameof(Widgets.Label), [typeof(Rect), typeof(string)]); + foreach (var inst in insts) + { + if (inst.Calls(labelMethod)) + { + yield return CodeInstruction.LoadArgument(2); // ModMetaData + yield return CodeInstruction.LoadArgument(0); // Page_ModsConfig + inst.operand = AccessTools.Method(typeof(PageModsConfigShowModCompat), nameof(DrawModLabel)); + } + + yield return inst; + } + } + + public static void DrawModLabel(Rect r, string label, ModMetaData mod, Page_ModsConfig parent) + { + if (!Multiplayer.settings.showModCompatibility) + { + Widgets.Label(r, label); + return; + } + + var compat = ModCompatibilityManager.LookupByMod(mod); + var rect = new Rect(r.x, (float) (r.y + r.height / 2.0 - 12.0), 20f, 24f); + Text.Anchor = TextAnchor.MiddleCenter; + + bool xml = MultiplayerData.IsXmlMod(mod); + var score = xml ? 4 : compat?.status ?? 0; + var scoreColor = ModCompatibility.ScoreColor(score); + Widgets.Label(rect, "[" + score.ToString().Colorize(scoreColor) + "]"); + + if (Mouse.IsOver(rect)) + { + var scoreText = (xml ? "MpModCompatXmlOnlyDesc" : ModCompatibility.ScoreDescription(score)).Translate(); + if (compat?.notes is { Length: > 0 }) + { + scoreText += $"\n{compat.notes}"; + } + + TooltipHandler.TipRegion(rect, () => scoreText, + (int)(r.x + r.y * 56167.0)); + Widgets.DrawHighlight(rect); + } + + if (Widgets.ButtonInvisible(rect)) + { + var modCompatWindow = new ModCompatWindow(parent, true, false, null); + modCompatWindow.ScrollToModName(mod.Name); + Find.WindowStack.Add(modCompatWindow); + } + + Text.Anchor = TextAnchor.MiddleLeft; + Widgets.Label(r.Right(rect.width + 4f), label); + } + } + [HarmonyPatch(typeof(Page_ModsConfig), nameof(Page_ModsConfig.DoBottomButtons))] static class PageModsConfigAddButton