mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-19 15:51:48 +00:00
add CreateAdvancedSettingsPage to print the settings
This commit is contained in:
1 parent
1e453cf6af
commit
5ec02eec9c
2 files changed
+140
-153
No files matched your search
@@ -1726,22 +1726,7 @@ public static class RoleGuidePatches
|
||||
// ---- General (non-role) option pages: paginated General tab + cross-page search ----
|
||||
private static Scroller? _generalScroller;
|
||||
private static GameObject? _generalNoResults;
|
||||
private static readonly List<GeneralRow> GeneralRows = [];
|
||||
private static GameObject? _generalRowTemplate;
|
||||
private static Vector3 _generalRowOrigin;
|
||||
private static Vector3 _generalRowColumnStep;
|
||||
private static float _generalRowHeight = -0.65f; // negative: rows go down
|
||||
private static int _generalColumns = 2;
|
||||
private static float _generalVisibleHeight;
|
||||
private static bool _generalScrollerFailed;
|
||||
|
||||
/// <summary>One vanilla-looking settings row (label box + value box) that is reused between pages.</summary>
|
||||
private sealed class GeneralRow(GameObject root, TextMeshPro label, TextMeshPro value)
|
||||
{
|
||||
public GameObject Root { get; } = root;
|
||||
public TextMeshPro Label { get; } = label;
|
||||
public TextMeshPro Value { get; } = value;
|
||||
}
|
||||
private static GameObject? _generalPageObject;
|
||||
private static List<GuideOptionPage> _generalPages = [];
|
||||
private static int _generalPage; // 0 = vanilla settings, 1..N = _generalPages[page - 1]
|
||||
private static bool _generalSearching;
|
||||
@@ -1760,17 +1745,27 @@ public static class RoleGuidePatches
|
||||
{
|
||||
_generalScroller = null;
|
||||
_generalNoResults = null;
|
||||
GeneralRows.Clear();
|
||||
_generalRowTemplate = null;
|
||||
_generalScrollerFailed = false;
|
||||
_generalPageObject = null;
|
||||
_generalPages = [];
|
||||
_generalPage = 0;
|
||||
_generalSearching = false;
|
||||
_sortButtonsRepurposed = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clones the roles tab to make the Settings tab. Used to display Options initialized by MiraAPI mods not related to roles or modifiers.
|
||||
/// </summary>
|
||||
private static void InitializeGeneralPanel(MatchInfoGuide instance)
|
||||
{
|
||||
var rolesTab = instance.settingsTabs[RolesTabIndex];
|
||||
var generalTab = Object.Instantiate(rolesTab, rolesTab.transform.parent);
|
||||
generalTab.name = "GeneralOptionsPanel";
|
||||
generalTab.transform.FindChild("MaskArea")?.transform.localPosition = new Vector3(-0.0184f, 0.15f, -0.1f);
|
||||
generalTab.transform.GetAllChildren()
|
||||
.First(x => x.name.Contains("BG_Gradient")).transform.localPosition = new Vector3(0, -0.62f, -5);
|
||||
_generalScroller = generalTab.GetComponent<Scroller>();
|
||||
generalTab.SetActive(false);
|
||||
|
||||
_generalNoResults = Object.Instantiate(
|
||||
instance.rolesEnabledMessage,
|
||||
instance.rolesEnabledMessage.transform.parent,
|
||||
@@ -1780,111 +1775,6 @@ public static class RoleGuidePatches
|
||||
SetNoResultsText(_generalNoResults);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clones the vanilla settings tab the first time it is needed, so extra pages are drawn with the exact same
|
||||
/// rows, fonts, masking and scroll area as the vanilla list. Done lazily because the vanilla rows are only
|
||||
/// created when the guide first opens. The clone is NOT added to <c>settingsTabs</c>; its visibility is managed
|
||||
/// here so the guide's tab count and tab buttons stay untouched.
|
||||
/// </summary>
|
||||
private static bool EnsureGeneralScroller(MatchInfoGuide guide)
|
||||
{
|
||||
if (_generalScroller != null && _generalRowTemplate)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_generalScrollerFailed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var vanillaTab = guide.settingsTabs[GeneralTabIndex];
|
||||
var vanillaScroller = vanillaTab.GetComponent<Scroller>() ?? vanillaTab.GetComponentInChildren<Scroller>(true);
|
||||
if (!vanillaScroller || vanillaScroller.Inner.childCount < 2)
|
||||
{
|
||||
return false; // vanilla rows not built yet; try again next refresh
|
||||
}
|
||||
|
||||
// Read the vanilla grid: first row, second entry (same row => 2 columns), third entry (next row).
|
||||
var vInner = vanillaScroller.Inner;
|
||||
var p0 = vInner.GetChild(0).localPosition;
|
||||
var p1 = vInner.GetChild(1).localPosition;
|
||||
var sameRow = Mathf.Abs(p1.y - p0.y) < 0.01f;
|
||||
var vanillaCount = vInner.childCount;
|
||||
_generalColumns = sameRow ? 2 : 1;
|
||||
_generalRowOrigin = p0;
|
||||
_generalRowColumnStep = sameRow ? new Vector3(p1.x - p0.x, 0f, 0f) : Vector3.zero;
|
||||
if (sameRow)
|
||||
{
|
||||
_generalRowHeight = vanillaCount >= 3 ? vInner.GetChild(2).localPosition.y - p0.y : -0.65f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_generalRowHeight = p1.y - p0.y;
|
||||
}
|
||||
|
||||
if (Mathf.Abs(_generalRowHeight) < 0.05f)
|
||||
{
|
||||
_generalRowHeight = -0.65f;
|
||||
}
|
||||
|
||||
// Self-calibrate the visible height from how the vanilla list was bounded.
|
||||
var vanillaRows = Mathf.CeilToInt(vanillaCount / (float)_generalColumns);
|
||||
var visible = (vanillaRows * Mathf.Abs(_generalRowHeight)) - vanillaScroller.ContentYBounds.max;
|
||||
_generalVisibleHeight = visible > 0.1f && visible < vanillaRows * Mathf.Abs(_generalRowHeight)
|
||||
? visible
|
||||
: 3.3f * Mathf.Abs(_generalRowHeight);
|
||||
|
||||
var clone = Object.Instantiate(vanillaTab, vanillaTab.transform.parent);
|
||||
clone.name = "GeneralOptionsPanel";
|
||||
var cloneScroller = clone.GetComponent<Scroller>() ?? clone.GetComponentInChildren<Scroller>(true);
|
||||
var cInner = cloneScroller.Inner;
|
||||
|
||||
// Keep the first row as an inactive prototype, delete the rest.
|
||||
var template = cInner.GetChild(0).gameObject;
|
||||
for (var i = cInner.childCount - 1; i >= 1; i--)
|
||||
{
|
||||
var child = cInner.GetChild(i).gameObject;
|
||||
child.SetActive(false);
|
||||
child.Destroy();
|
||||
}
|
||||
|
||||
template.SetActive(false);
|
||||
_generalRowTemplate = template;
|
||||
_generalScroller = cloneScroller;
|
||||
clone.SetActive(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static GeneralRow? CreateGeneralRow()
|
||||
{
|
||||
if (_generalScroller == null || !_generalRowTemplate)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var go = Object.Instantiate(_generalRowTemplate!, _generalScroller.Inner);
|
||||
go.name = "GeneralOptionRow";
|
||||
|
||||
// The game would re-translate these and overwrite our text.
|
||||
foreach (var translator in go.GetComponentsInChildren<TextTranslatorTMP>(true))
|
||||
{
|
||||
translator.Destroy();
|
||||
}
|
||||
|
||||
// Label is the left-most text, value is the right-most (same as the vanilla entries).
|
||||
var texts = go.GetComponentsInChildren<TextMeshPro>(true).OrderBy(t => t.transform.position.x).ToArray();
|
||||
if (texts.Length < 2)
|
||||
{
|
||||
Warning("Vanilla settings row has fewer than two text fields; cannot clone it for the general pages.");
|
||||
go.Destroy();
|
||||
_generalScrollerFailed = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
return new GeneralRow(go, texts[0], texts[^1]);
|
||||
}
|
||||
|
||||
private static void EnterGeneralTab()
|
||||
{
|
||||
if (!_uiInitialized)
|
||||
@@ -1983,45 +1873,29 @@ public static class RoleGuidePatches
|
||||
private static void ShowGeneralEntries(IReadOnlyList<GuideOptionEntry> entries, bool showGroup, bool scrollToTop)
|
||||
{
|
||||
var guide = MatchInfoGuide.Instance;
|
||||
if (!guide || !EnsureGeneralScroller(guide))
|
||||
if (_generalScroller == null || !guide || !guide.MatchInfoRolePanelPrefab)
|
||||
{
|
||||
// Could not clone the vanilla rows: fall back to the plain vanilla tab rather than a blank page.
|
||||
// Never leave the tab blank: fall back to the plain vanilla list.
|
||||
guide?.settingsTabs[GeneralTabIndex].SetActive(true);
|
||||
return;
|
||||
}
|
||||
|
||||
while (GeneralRows.Count < entries.Count)
|
||||
if (_generalPageObject)
|
||||
{
|
||||
var row = CreateGeneralRow();
|
||||
if (row == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
GeneralRows.Add(row);
|
||||
_generalPageObject!.SetActive(false);
|
||||
_generalPageObject.Destroy();
|
||||
_generalPageObject = null;
|
||||
}
|
||||
|
||||
for (var i = 0; i < GeneralRows.Count; i++)
|
||||
var rows = new List<KeyValuePair<string, string>>(entries.Count);
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
var row = GeneralRows[i];
|
||||
if (i >= entries.Count)
|
||||
{
|
||||
row.Root.SetActive(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
var entry = entries[i];
|
||||
row.Label.text = showGroup ? $"<size=60%>{entry.GroupName}</size>\n{entry.Title}" : entry.Title;
|
||||
row.Value.text = entry.Value;
|
||||
row.Root.transform.localPosition = _generalRowOrigin +
|
||||
(_generalRowColumnStep * (i % _generalColumns)) +
|
||||
new Vector3(0f, _generalRowHeight * (i / _generalColumns), 0f);
|
||||
row.Root.SetActive(true);
|
||||
var label = showGroup ? $"<size=60%>{entry.GroupName}</size>\n{entry.Title}" : entry.Title;
|
||||
rows.Add(new KeyValuePair<string, string>(label, entry.Value));
|
||||
}
|
||||
|
||||
var rows = Mathf.CeilToInt(Mathf.Min(entries.Count, GeneralRows.Count) / (float)_generalColumns);
|
||||
_generalScroller!.gameObject.SetActive(true);
|
||||
_generalScroller.SetYBoundsMax(Mathf.Clamp((rows * Mathf.Abs(_generalRowHeight)) - _generalVisibleHeight, 0f, 999f));
|
||||
_generalScroller.gameObject.SetActive(true);
|
||||
_generalPageObject = Helpers.CreateAdvancedSettingsPage(guide, _generalScroller, rows);
|
||||
_generalNoResults?.SetActive(entries.Count == 0);
|
||||
if (scrollToTop)
|
||||
{
|
||||
|
||||
@@ -844,6 +844,119 @@ public static class Helpers
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a page of vanilla-looking settings rows (label box on the left, value box on the right, two columns)
|
||||
/// inside a roles-style scroller. Use this for lists of "Name: Value" settings that are not roles or modifiers.
|
||||
/// </summary>
|
||||
/// <param name="guide">The guide object.</param>
|
||||
/// <param name="parent">The <see cref="Scroller"/> the page is parented to.</param>
|
||||
/// <param name="settings">The rows to show: key is the label, value is the displayed value.</param>
|
||||
/// <returns>The <see cref="GameObject"/> that holds all the rows. Destroy it to remove the page.</returns>
|
||||
public static GameObject CreateAdvancedSettingsPage(
|
||||
MatchInfoGuide guide,
|
||||
Scroller parent,
|
||||
IReadOnlyList<KeyValuePair<string, string>> settings)
|
||||
{
|
||||
const float rowHeight = 0.4f;
|
||||
const float rowPitch = 0.52f;
|
||||
const float contentTop = 0.95f;
|
||||
const float visibleHeight = 1.5f;
|
||||
const int columns = 2;
|
||||
|
||||
var inner = parent.Inner;
|
||||
var layout = inner.GetComponent<GridLayoutGroup>();
|
||||
if (layout)
|
||||
{
|
||||
layout.enabled = false;
|
||||
}
|
||||
|
||||
var columnWidth = layout ? Mathf.Clamp(layout.cellSize.x, 2f, 3.2f) : 2.7f;
|
||||
var columnGap = layout ? Mathf.Clamp(layout.spacing.x, 0.1f, 0.6f) : 0.3f;
|
||||
var labelWidth = columnWidth * 0.62f;
|
||||
var valueWidth = columnWidth * 0.30f;
|
||||
var boxGap = columnWidth - labelWidth - valueWidth;
|
||||
var left = -((columns * columnWidth) + ((columns - 1) * columnGap)) / 2f;
|
||||
|
||||
var prefab = guide.MatchInfoRolePanelPrefab;
|
||||
var vanillaFont = HudManager.Instance.TaskPanel.taskText;
|
||||
|
||||
var boxMaterial = new Material(prefab.roleIcon.sharedMaterial);
|
||||
boxMaterial.SetInt(PlayerMaterial.MaskLayer, 50);
|
||||
var boxSprite = MiraAssets.BlankSprite.LoadAsset();
|
||||
var layer = inner.gameObject.layer;
|
||||
|
||||
var page = new GameObject("AdvancedSettingsPage") { layer = layer };
|
||||
page.transform.SetParent(inner, false);
|
||||
page.transform.localPosition = Vector3.zero;
|
||||
|
||||
void MakeBox(Vector3 pos, Vector2 size, Color color)
|
||||
{
|
||||
var box = new GameObject("Box") { layer = layer };
|
||||
box.transform.SetParent(page.transform, false);
|
||||
box.transform.localPosition = pos;
|
||||
var sr = box.AddComponent<SpriteRenderer>();
|
||||
sr.sprite = boxSprite;
|
||||
sr.drawMode = SpriteDrawMode.Sliced;
|
||||
sr.size = size;
|
||||
sr.color = color;
|
||||
sr.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
|
||||
sr.sharedMaterial = boxMaterial;
|
||||
}
|
||||
|
||||
void MakeText(string text, Vector3 pos, Vector2 size)
|
||||
{
|
||||
var tmp = Object.Instantiate(prefab.roleName, page.transform);
|
||||
tmp.richText = true;
|
||||
tmp.font = vanillaFont.font;
|
||||
tmp.fontMaterial = vanillaFont.fontMaterial;
|
||||
tmp.text = text;
|
||||
tmp.enableAutoSizing = true;
|
||||
tmp.fontSizeMin = 0.9f;
|
||||
tmp.fontSizeMax = 2.2f;
|
||||
tmp.fontStyle = FontStyles.Normal;
|
||||
tmp.enableWordWrapping = true;
|
||||
tmp.alignment = TextAlignmentOptions.Center;
|
||||
tmp.color = Color.white;
|
||||
tmp.rectTransform.sizeDelta = size;
|
||||
tmp.transform.localPosition = pos;
|
||||
tmp.EnableStencilMasking();
|
||||
}
|
||||
|
||||
for (var i = 0; i < settings.Count; i++)
|
||||
{
|
||||
var col = i % columns;
|
||||
var row = i / columns;
|
||||
var originX = left + (col * (columnWidth + columnGap));
|
||||
var centerY = contentTop - (rowHeight / 2f) - (row * rowPitch);
|
||||
|
||||
var labelX = originX + (labelWidth / 2f);
|
||||
var valueX = originX + labelWidth + boxGap + (valueWidth / 2f);
|
||||
|
||||
MakeBox(
|
||||
new Vector3(labelX, centerY, 0f),
|
||||
new Vector2(labelWidth, rowHeight),
|
||||
new Color(0.16f, 0.16f, 0.16f, 1f));
|
||||
MakeBox(new Vector3(valueX, centerY, -0.01f), new Vector2(valueWidth, rowHeight), Color.white);
|
||||
MakeBox(
|
||||
new Vector3(valueX, centerY, -0.02f),
|
||||
new Vector2(valueWidth - 0.04f, rowHeight - 0.04f),
|
||||
Color.black);
|
||||
|
||||
MakeText(
|
||||
$"<b>{settings[i].Key}</b>",
|
||||
new Vector3(labelX, centerY, -0.1f),
|
||||
new Vector2(labelWidth - 0.12f, rowHeight - 0.04f));
|
||||
MakeText(
|
||||
settings[i].Value,
|
||||
new Vector3(valueX, centerY, -0.1f),
|
||||
new Vector2(valueWidth - 0.1f, rowHeight - 0.04f));
|
||||
}
|
||||
|
||||
var rows = Mathf.CeilToInt(settings.Count / (float)columns);
|
||||
parent.SetYBoundsMax(Mathf.Clamp((rows * rowPitch) - visibleHeight, 0f, 999f));
|
||||
return page;
|
||||
}
|
||||
|
||||
private static void SetupAbilityPanel(MatchInfoRolePanel panel, AdvancedWikiAbilityDescription ability, bool variableTextSizing = false)
|
||||
{
|
||||
panel.roleCount.text = ability.AbilityType;
|
||||
@@ -868,4 +981,4 @@ public static class Helpers
|
||||
panel.roleCount.fontMaterial.SetFloat(panel.STENCIL_NAME, 50f);
|
||||
panel.roleIcon.transform.localScale = new Vector3(3.5f, 3.5f, 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user