Show role/modifier icons on wiki pages, fix wiki softlock after rejoining, even out sort buttons

This commit is contained in:
ReAdmin committed 2026-10-08 20:15:16 -07:00
1 parent b6bddbd0df
commit 317fd243b1
4 files changed
+130 -10

No files matched your search

+1 -1
View File
@@ -117,7 +117,7 @@ public abstract class BaseModifier : IOptionable
titleText,
parent,
ModifierNameLocale,
ModifierName + $" ({ModifierCategoryTitle})",
$"{this.GetTmpIcon()} {ModifierName} ({ModifierCategoryTitle})".TrimStart(),
ModifierWikiDescription,
abilities);
}
+67 -4
View File
@@ -109,6 +109,56 @@ public static class RoleGuidePatches
public static void Awake(MatchInfoGuide __instance)
{
__instance.transitionOpen.targetSize = 1.3f;
if (_guide != __instance)
{
ResetState();
}
}
/// <summary>
/// Clears all cached state tied to a previous <see cref="MatchInfoGuide"/> instance.
/// Every game spawns a fresh guide, so anything we cached from the old one is a destroyed Unity object.
/// </summary>
private static void ResetState()
{
if (_populate != null)
{
Coroutines.Stop(_populate);
_populate = null;
}
if (_searchDebounce != null)
{
Coroutines.Stop(_searchDebounce);
_searchDebounce = null;
}
RoleEntries.Clear();
ModifierEntries.Clear();
_guide = null;
_uiInitialized = false;
_loading = false;
_appliedSearch = string.Empty;
_suppressSearchRefresh = false;
_titleText = null!;
_searchBoxTmp = null!;
_rolesScroller = null!;
_modifiersScroller = null!;
_advancedInfoTabScroller = null!;
_currentAdvancedTabObject = null!;
_loadingSpinner = null;
SearchIconButton = null!;
SearchSortingOrderButton = null!;
SearchSortingGroupButton = null!;
SearchSortingFilterButton = null!;
_searchIconIdle = null!;
_searchIconHover = null!;
_searchSortingOrderIdle = null!;
_searchSortingOrderHover = null!;
_searchSortingGroupIdle = null!;
_searchSortingGroupHover = null!;
_searchSortingFilterIdle = null!;
_searchSortingFilterHover = null!;
}
[HarmonyPostfix]
@@ -156,6 +206,11 @@ public static class RoleGuidePatches
[HarmonyPatch(typeof(MatchInfoGuide), nameof(MatchInfoGuide.Open))]
public static bool Open(MatchInfoGuide __instance)
{
if (!HudManager.InstanceExists || !GameManager.Instance || !PlayerControl.LocalPlayer)
{
return false;
}
if (HudManager.Instance.GameMenu.IsOpen || HudManager.Instance.Chat.IsOpenOrOpening)
{
return false;
@@ -311,7 +366,7 @@ public static class RoleGuidePatches
SwitchGrouping,
MiraAssets.GroupNoneIdleSprite,
MiraAssets.GroupNoneHoverSprite,
new Vector3(1.8f, 0.765f, -0.1f),
new Vector3(1.7f, 0.765f, -0.1f),
out _searchSortingGroupIdle,
out _searchSortingGroupHover);
@@ -894,8 +949,16 @@ public static class RoleGuidePatches
}
_appliedSearch = string.Empty;
_searchIconIdle.sprite = MiraAssets.SearchIconIdleSprite;
_searchIconHover.sprite = MiraAssets.SearchIconHoverSprite;
if (_searchIconIdle)
{
_searchIconIdle.sprite = MiraAssets.SearchIconIdleSprite;
}
if (_searchIconHover)
{
_searchIconHover.sprite = MiraAssets.SearchIconHoverSprite;
}
if (_searchBoxTmp && GetSearchText().Length > 0)
{
_suppressSearchRefresh = true;
@@ -1177,7 +1240,7 @@ public static class RoleGuidePatches
}
else
{
var titleTxt = role.GetRoleName() +
var titleTxt = $"{role.GetTmpIcon()} {role.GetRoleName()}" +
$" ({TranslationController.Instance.GetString(role.TeamType is RoleTeamTypes.Crewmate ? StringNames.Crewmate : StringNames.Impostor)})";
var description = TranslationController.Instance.GetString(role.BlurbNameLong);
if (description.Contains("STRMISS"))
+1 -1
View File
@@ -328,7 +328,7 @@ public interface ICustomRole : IOptionable
titleText,
parent,
RoleNameLocale,
RoleName + $" ({RoleFactionTitle})",
$"{this.GetTmpIcon()} {RoleName} ({RoleFactionTitle})",
RoleWikiDescription,
abilities);
}
+61 -4
View File
@@ -11,6 +11,7 @@ using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using MiraAPI.GameOptions;
using MiraAPI.GameOptions.OptionTypes;
using MiraAPI.Modifiers;
using MiraAPI.Roles;
using MiraAPI.Translation;
using MiraAPI.Utilities.Assets;
@@ -688,6 +689,40 @@ public static class Helpers
return role is ICustomRole custom ? custom.RoleLongDescription : role.BlurbLong;
}
/// <summary>
/// Returns the TextMeshPro sprite tag for a role, matching how role names are shown in-game.
/// Uses the role's <see cref="CustomRoleConfiguration.IconTmp"/> if set, otherwise falls back to the faction icon.
/// </summary>
/// <param name="role">The <see cref="RoleBehaviour"/>.</param>
/// <returns>A <c>&lt;sprite&gt;</c> rich text tag.</returns>
public static string GetTmpIcon(this RoleBehaviour role)
{
return role is ICustomRole custom ? custom.GetTmpIcon() : $"<sprite name=\"AmongUs.Role.{role.Role}\">";
}
/// <summary>
/// Returns the TextMeshPro sprite tag for a custom role, matching how role names are shown in-game.
/// Uses the role's <see cref="CustomRoleConfiguration.IconTmp"/> if set, otherwise falls back to the faction icon.
/// </summary>
/// <param name="role">The <see cref="ICustomRole"/>.</param>
/// <returns>A <c>&lt;sprite&gt;</c> rich text tag.</returns>
public static string GetTmpIcon(this ICustomRole role)
{
return role.Configuration.IconTmp
? $"<sprite name=\"{role.Configuration.IconTmp.name}\">"
: $"<sprite name=\"AmongUs.Role.{role.Team}\">";
}
/// <summary>
/// Returns the TextMeshPro sprite tag for a modifier, or an empty string if it has no <see cref="BaseModifier.IconTmp"/>.
/// </summary>
/// <param name="modifier">The <see cref="BaseModifier"/>.</param>
/// <returns>A <c>&lt;sprite&gt;</c> rich text tag, or <see cref="string.Empty"/>.</returns>
public static string GetTmpIcon(this BaseModifier modifier)
{
return modifier.IconTmp ? $"<sprite name=\"{modifier.IconTmp.name}\">" : string.Empty;
}
/// <summary>
/// Returns whether the <see cref="RoleBehaviour"/> is blacklisted from appearing and spawning. (Only applicable to vanilla roles).
/// </summary>
@@ -713,6 +748,7 @@ public static class Helpers
public static GameObject CreateAdvancedWikiTab(MatchInfoGuide guide, string objName, string title, string description, TextMeshPro titleTmp, out TextMeshPro descriptionTmp)
{
var obj = new GameObject(objName);
titleTmp.richText = true;
titleTmp.text = title;
descriptionTmp = Object.Instantiate(guide.MatchInfoRolePanelPrefab.roleCount, obj.transform);
descriptionTmp.fontSizeMin = descriptionTmp.fontSizeMax = descriptionTmp.fontSize = 2f;
@@ -738,6 +774,7 @@ public static class Helpers
/// <param name="title">The title of the page.</param>
/// <param name="description">The description of the page.</param>
/// <param name="abilities">The abilities to display in a grid below the description.</param>
/// <param name="variableTextSizing">Whether to use variable text sizing for ability descriptions (allows different heights).</param>
/// <returns>The <see cref="GameObject"/> of the wiki page.</returns>
public static GameObject CreateAdvancedWikiPage(
MatchInfoGuide guide,
@@ -746,7 +783,8 @@ public static class Helpers
string objName,
string title,
string description,
IReadOnlyCollection<AdvancedWikiAbilityDescription> abilities)
IReadOnlyCollection<AdvancedWikiAbilityDescription> abilities,
bool variableTextSizing = false)
{
parent.ScrollToTop();
var obj = CreateAdvancedWikiTab(
@@ -757,6 +795,7 @@ public static class Helpers
titleTmp,
out var desc);
var num = 0;
var maxTextSize = 0f;
if (abilities.Count != 0)
{
var grid = Object.Instantiate(parent.Inner, obj.transform);
@@ -768,7 +807,16 @@ public static class Helpers
foreach (var ability in abilities)
{
num++;
SetupAbilityPanel(Object.Instantiate(guide.MatchInfoRolePanelPrefab, grid), ability);
var panel = Object.Instantiate(guide.MatchInfoRolePanelPrefab, grid);
SetupAbilityPanel(panel, ability, variableTextSizing);
if (variableTextSizing)
{
var descSize = panel.roleDescription.textBounds.size.y;
if (maxTextSize < descSize)
{
maxTextSize = descSize;
}
}
}
grid.localPosition = new Vector3(-3.9f, 1.1f - desc.textBounds.size.y, 0f);
@@ -777,11 +825,14 @@ public static class Helpers
obj.transform.SetParent(parent.Inner.transform);
obj.transform.localPosition = new Vector3(0f, 0f, 0f);
parent.SetYBoundsMax(Mathf.Clamp(desc.textBounds.size.y - 2 + Mathf.Ceil(num / 2f) * 1.45f, 0f, 999f));
var scrollHeight = variableTextSizing
? (desc.textBounds.size.y - 2) + maxTextSize + 0.475f
: desc.textBounds.size.y - 2 + Mathf.Ceil(num / 2f) * 1.45f;
parent.SetYBoundsMax(Mathf.Clamp(scrollHeight, 0f, 999f));
return obj;
}
private static void SetupAbilityPanel(MatchInfoRolePanel panel, AdvancedWikiAbilityDescription ability)
private static void SetupAbilityPanel(MatchInfoRolePanel panel, AdvancedWikiAbilityDescription ability, bool variableTextSizing = false)
{
panel.roleCount.text = ability.AbilityType;
panel.roleCount.transform.localPosition += new Vector3(-0.04f, 0);
@@ -790,6 +841,12 @@ public static class Helpers
panel.roleDescription.text = ability.Description;
panel.roleDescription.rectTransform.sizeDelta = new Vector2(2.601f, 0.8f);
panel.roleDescription.transform.localPosition += new Vector3(0, -0.1f);
if (variableTextSizing)
{
panel.roleDescription.alignment = TextAlignmentOptions.Top;
panel.roleDescription.fontSizeMin = 1.5f;
panel.roleDescription.ForceMeshUpdate();
}
panel.roleIcon.sprite = ability.Icon.LoadAsset();
panel.roleIcon.SetSizeLimit(0.13f);