mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 01:46:15 +00:00
change custom menu behaviour to wrap a script instead
This commit is contained in:
4 files changed
+220
-169
No files matched your search
@@ -1,30 +1,22 @@
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.Patches.Stubs;
|
||||
using MiraAPI.Patches.Stubs;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
#pragma warning disable S2365 // Properties should not make collection or array copies
|
||||
|
||||
namespace MiraAPI.Hud;
|
||||
|
||||
/// <summary>
|
||||
/// Multi-select <see cref="CustomPhoneMenu"/> using the <see cref="ShapeshifterPanel"/> as a base.
|
||||
/// </summary>
|
||||
/// <param name="il2CppPtr">Used by Il2Cpp. Do not use constructor, this is a <see cref="MonoBehaviour"/>.</param>
|
||||
/// <typeparam name="TEntry">The type of object each entry represents.</typeparam>
|
||||
[RegisterInIl2Cpp]
|
||||
[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity Convention")]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Unity Convention")]
|
||||
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Unity Convention")]
|
||||
public abstract class CustomMultiSelectMenu<TEntry>(IntPtr il2CppPtr)
|
||||
: CustomPhoneMenu<CustomMultiSelectMenu<TEntry>.MenuEntry>(il2CppPtr) where TEntry : class
|
||||
[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity convention.")]
|
||||
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Read above.")]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Read above.")]
|
||||
public abstract class CustomMultiSelectMenu<TEntry> : CustomPhoneMenu<CustomMultiSelectMenu<TEntry>.MenuEntry> where TEntry : class
|
||||
{
|
||||
private int totalSelections;
|
||||
private bool shouldConfirm;
|
||||
@@ -37,10 +29,18 @@ public abstract class CustomMultiSelectMenu<TEntry>(IntPtr il2CppPtr)
|
||||
private Color? hoverSelectColor;
|
||||
private Color? hoverDeselectColor;
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
[SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Unity convention.")]
|
||||
public UiElement confirmButton;
|
||||
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
private Action<List<TEntry>>? onSelection;
|
||||
|
||||
/// <summary>
|
||||
/// Menu Entry used when multiple entries are at play.
|
||||
/// </summary>
|
||||
/// <param name="Panel">The panel of the entry.</param>
|
||||
/// <param name="Entry">The entry itself.</param>
|
||||
public record MenuEntry(ShapeshifterPanel Panel, TEntry Entry) : IMenuEntry;
|
||||
|
||||
/// <summary>
|
||||
@@ -63,7 +63,7 @@ public abstract class CustomMultiSelectMenu<TEntry>(IntPtr il2CppPtr)
|
||||
Color? hoverDeselectColor = null,
|
||||
PanelButtonOnMouse? onMouseOut = null,
|
||||
PanelButtonOnMouse? onMouseOver = null
|
||||
) where TMenu : CustomMultiSelectMenu<TEntry>
|
||||
) where TMenu : CustomMultiSelectMenu<TEntry>, new()
|
||||
{
|
||||
TMenu customMenu = Create<TMenu>(onMouseOut, onMouseOver);
|
||||
|
||||
@@ -101,10 +101,9 @@ public abstract class CustomMultiSelectMenu<TEntry>(IntPtr il2CppPtr)
|
||||
/// <param name="totalSelections">The number of selections required.</param>
|
||||
/// <param name="shouldConfirm">Whether the entire selection should be confirmed manually.</param>
|
||||
/// <param name="canRepeat">If the same entry can be selected multiple times, else unselect entry on click.</param>
|
||||
[HideFromIl2Cpp]
|
||||
protected void Begin(IEnumerable<TEntry> entries, Action<List<TEntry>?> onClick, int totalSelections, bool shouldConfirm, bool canRepeat = false)
|
||||
{
|
||||
MinigameStubs.Begin(this, null);
|
||||
MinigameStubs.Begin(Component, null);
|
||||
|
||||
this.totalSelections = totalSelections;
|
||||
this.shouldConfirm = shouldConfirm;
|
||||
@@ -118,7 +117,7 @@ public abstract class CustomMultiSelectMenu<TEntry>(IntPtr il2CppPtr)
|
||||
onClick(null);
|
||||
}));
|
||||
|
||||
DebugAnalytics.Instance.Analytics.MinigameOpened(PlayerControl.LocalPlayer.Data, TaskType);
|
||||
DebugAnalytics.Instance.Analytics.MinigameOpened(PlayerControl.LocalPlayer.Data, Component.TaskType);
|
||||
var list2 = new Il2CppSystem.Collections.Generic.List<UiElement>();
|
||||
RegisterPanels(
|
||||
entries,
|
||||
@@ -140,7 +139,6 @@ public abstract class CustomMultiSelectMenu<TEntry>(IntPtr il2CppPtr)
|
||||
/// <param name="entries">All entries to give the custom menu.</param>
|
||||
/// <param name="onClick">Function called when the selection is made.</param>
|
||||
/// <param name="shouldConfirm">Whether the set of both selections should be confirmed manually.</param>
|
||||
[HideFromIl2Cpp]
|
||||
protected void Begin(IEnumerable<TEntry> entries, Action<TEntry?> onClick, bool shouldConfirm)
|
||||
{
|
||||
Begin(entries, list => onClick(list?[0]), 1, shouldConfirm);
|
||||
@@ -153,7 +151,6 @@ public abstract class CustomMultiSelectMenu<TEntry>(IntPtr il2CppPtr)
|
||||
/// <param name="onClick">Function called when both selections are made.</param>
|
||||
/// <param name="shouldConfirm">Whether the set of both selections should be confirmed manually.</param>
|
||||
/// <param name="canRepeat">If the same entry can be selected both times, else unselect entry on click.</param>
|
||||
[HideFromIl2Cpp]
|
||||
protected void Begin(IEnumerable<TEntry> entries, Action<TEntry?, TEntry?> onClick, bool shouldConfirm, bool canRepeat = false)
|
||||
{
|
||||
Begin(entries, list => onClick(list?[0], list?[1]), 2, shouldConfirm, canRepeat);
|
||||
@@ -198,7 +195,7 @@ public abstract class CustomMultiSelectMenu<TEntry>(IntPtr il2CppPtr)
|
||||
|
||||
private void OnCompleteSelection()
|
||||
{
|
||||
onSelection!(selectedEntries.Select(se => se.Entry).ToList());
|
||||
onSelection!([.. selectedEntries.Select(se => se.Entry)]);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -210,7 +207,6 @@ public abstract class CustomMultiSelectMenu<TEntry>(IntPtr il2CppPtr)
|
||||
/// <inheritdoc cref="CustomPhoneMenu.SetNameplateAppearance(IMenuEntry, LoadableAsset{Sprite}?, Color?, Color?)"/>
|
||||
/// <param name="menuEntry"></param>
|
||||
/// <param name="isSelected">Whether the menu entry is actively selected.</param>
|
||||
[HideFromIl2Cpp]
|
||||
protected void SetNameplateAppearance(IMenuEntry menuEntry, bool isSelected)
|
||||
{
|
||||
SetNameplateAppearance(
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.Patches.Stubs;
|
||||
using MiraAPI.Patches.Stubs;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Collections;
|
||||
@@ -13,38 +11,49 @@ using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
#pragma warning disable S2365 // Properties should not make collection or array copies
|
||||
using CppCollections = Il2CppSystem.Collections.Generic;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.Hud;
|
||||
|
||||
/// <summary>
|
||||
/// Paginable <see cref="CustomPhoneMenu"/> using the <see cref="ShapeshifterPanel"/> as a base.
|
||||
/// </summary>
|
||||
/// <param name="il2CppPtr">Used by Il2Cpp. Do not use constructor, this is a <see cref="MonoBehaviour"/>.</param>
|
||||
[RegisterInIl2Cpp]
|
||||
[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity Convention")]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Unity Convention")]
|
||||
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Unity Convention")]
|
||||
public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<CustomPaginableMenu.MenuEntry>(il2CppPtr)
|
||||
[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity convention.")]
|
||||
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Read above.")]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Read above.")]
|
||||
public abstract class CustomPaginableMenu : CustomPhoneMenu<CustomPaginableMenu.MenuEntry>
|
||||
{
|
||||
/// <summary>
|
||||
/// Menu Entry used for when multiple pages are needed.
|
||||
/// </summary>
|
||||
/// <param name="Panel">The panel.</param>
|
||||
/// <param name="SortKey">The key by which the panels are sorted.</param>
|
||||
public record MenuEntry(ShapeshifterPanel Panel, string SortKey) : IMenuEntry;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the menu.
|
||||
/// </summary>
|
||||
protected abstract string Name { get; }
|
||||
|
||||
protected int currentPage;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the prefab used to generate the search field.
|
||||
/// </summary>
|
||||
protected abstract TextBoxTMP? PrefabTextbox { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override float MenuDepth => -60f;
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
protected int currentPage;
|
||||
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
private TextBoxTMP? searchTextbox;
|
||||
private string searchText = string.Empty;
|
||||
private TextMeshPro? noResultsText;
|
||||
|
||||
private const int ItemsPerPage = 15;
|
||||
|
||||
protected override float MenuDepth => -60f;
|
||||
|
||||
public record MenuEntry(ShapeshifterPanel Panel, string SortKey) : IMenuEntry;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <typeparamref name="TMenu"/>.
|
||||
/// </summary>
|
||||
@@ -52,14 +61,11 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
/// <param name="onMouseOut">Function that can optionally be run when the mouse is moved outside a menu panel.</param>
|
||||
/// <param name="onMouseOver">Function that can optionally be run when the mouse is moved over a menu panel.</param>
|
||||
/// <returns>New <typeparamref name="TMenu"/> object.</returns>
|
||||
protected static new TMenu Create<TMenu>(
|
||||
PanelButtonOnMouse? onMouseOut = null,
|
||||
PanelButtonOnMouse? onMouseOver = null
|
||||
) where TMenu : CustomPaginableMenu
|
||||
protected static new TMenu Create<TMenu>(PanelButtonOnMouse? onMouseOut = null, PanelButtonOnMouse? onMouseOver = null) where TMenu : CustomPaginableMenu, new()
|
||||
{
|
||||
TMenu customMenu = CustomPhoneMenu.Create<TMenu>(onMouseOut, onMouseOver);
|
||||
|
||||
var nextButton = Instantiate(customMenu.backButton, customMenu.transform).gameObject;
|
||||
var nextButton = Object.Instantiate(customMenu.backButton, customMenu.transform).gameObject;
|
||||
nextButton.transform.localPosition = new Vector3(1.85f, -2.185f, customMenu.MenuDepth);
|
||||
nextButton.transform.localScale = new Vector3(0.65f, 0.65f, 1);
|
||||
nextButton.name = "RightArrowButton";
|
||||
@@ -70,7 +76,7 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
passiveButton.OnClick = new Button.ButtonClickedEvent();
|
||||
passiveButton.OnClick.AddListener((UnityAction)customMenu.NextPage);
|
||||
|
||||
var backButton = Instantiate(nextButton, customMenu.transform).gameObject;
|
||||
var backButton = Object.Instantiate(nextButton, customMenu.transform).gameObject;
|
||||
backButton.transform.localPosition = new Vector3(-1.85f, -2.185f, customMenu.MenuDepth);
|
||||
backButton.name = "LeftArrowButton";
|
||||
backButton.gameObject.GetComponent<CloseButtonConsoleBehaviour>().Destroy();
|
||||
@@ -93,22 +99,19 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
: text.Trim().ToLowerInvariant();
|
||||
}
|
||||
|
||||
[HideFromIl2Cpp]
|
||||
private List<MenuEntry> GetFilteredEntries()
|
||||
{
|
||||
var query = NormalizeForSearch(searchText);
|
||||
if (string.IsNullOrEmpty(query))
|
||||
{
|
||||
return MenuEntries;
|
||||
}
|
||||
|
||||
return MenuEntries
|
||||
if (string.IsNullOrEmpty(query))
|
||||
return MenuEntries;
|
||||
|
||||
return [.. MenuEntries
|
||||
.Where(e => e.SortKey.Contains(query, StringComparison.OrdinalIgnoreCase))
|
||||
.OrderByDescending(e => e.SortKey.Equals(query, StringComparison.OrdinalIgnoreCase))
|
||||
.ThenByDescending(e => e.SortKey.StartsWith(query, StringComparison.OrdinalIgnoreCase))
|
||||
.ThenByDescending(e => e.SortKey.Contains(query, StringComparison.OrdinalIgnoreCase))
|
||||
.ThenBy(e => e.SortKey, StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
.ThenBy(e => e.SortKey, StringComparer.OrdinalIgnoreCase)];
|
||||
}
|
||||
|
||||
private static int GetTotalPages(int itemCount)
|
||||
@@ -116,7 +119,7 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
return Mathf.Max(1, Mathf.CeilToInt(itemCount / (float)ItemsPerPage));
|
||||
}
|
||||
|
||||
private void RefreshControllerOverlay(Il2CppSystem.Collections.Generic.List<UiElement> list)
|
||||
private void RefreshControllerOverlay(CppCollections.List<UiElement> list)
|
||||
{
|
||||
if (ControllerManager.Instance && backButton != null)
|
||||
{
|
||||
@@ -124,7 +127,6 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
}
|
||||
}
|
||||
|
||||
[HideFromIl2Cpp]
|
||||
private IEnumerator CoRestoreFocus()
|
||||
{
|
||||
yield return null;
|
||||
@@ -149,7 +151,11 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
RefreshControllerOverlay(list);
|
||||
}
|
||||
|
||||
public Il2CppSystem.Collections.Generic.List<UiElement> ShowPage()
|
||||
/// <summary>
|
||||
/// Shows the current page.
|
||||
/// </summary>
|
||||
/// <returns>The Il2CPP list of ui elements displayed on the page.</returns>
|
||||
public CppCollections.List<UiElement> ShowPage()
|
||||
{
|
||||
foreach (var entry in MenuEntries)
|
||||
{
|
||||
@@ -162,7 +168,7 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
currentPage = Mathf.Clamp(currentPage, 0, totalPages - 1);
|
||||
|
||||
var list = filtered.Skip(currentPage * ItemsPerPage).Take(ItemsPerPage).ToList();
|
||||
var list2 = new Il2CppSystem.Collections.Generic.List<UiElement>();
|
||||
var list2 = new CppCollections.List<UiElement>();
|
||||
|
||||
for (var i = 0; i < list.Count; i++)
|
||||
{
|
||||
@@ -178,7 +184,9 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
return list2;
|
||||
}
|
||||
|
||||
[HideFromIl2Cpp]
|
||||
/// <summary>
|
||||
/// Ensures that the search UI exists.
|
||||
/// </summary>
|
||||
protected void EnsureSearchUi()
|
||||
{
|
||||
if (searchTextbox != null)
|
||||
@@ -195,7 +203,7 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
}
|
||||
|
||||
var searchRoot = PrefabTextbox.transform.parent != null ? PrefabTextbox.transform.parent.gameObject : PrefabTextbox.gameObject;
|
||||
var searchObj = Instantiate(searchRoot, transform);
|
||||
var searchObj = Object.Instantiate(searchRoot, transform);
|
||||
searchObj.name = $"{Name}SearchBar";
|
||||
|
||||
foreach (var aspect in searchObj.GetComponentsInChildren<AspectPosition>(true))
|
||||
@@ -265,7 +273,7 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
}
|
||||
}));
|
||||
|
||||
var label = Instantiate(HudManager.Instance?.TaskPanel.taskText, transform);
|
||||
var label = Object.Instantiate(HudManager.Instance?.TaskPanel.taskText, transform);
|
||||
if (label != null)
|
||||
{
|
||||
label.name = $"{Name}SearchLabel";
|
||||
@@ -282,7 +290,7 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
}
|
||||
}
|
||||
|
||||
noResultsText = Instantiate(HudManager.Instance?.TaskPanel.taskText, transform);
|
||||
noResultsText = Object.Instantiate(HudManager.Instance?.TaskPanel.taskText, transform);
|
||||
if (noResultsText != null)
|
||||
{
|
||||
noResultsText.name = $"{Name}NoResultsText";
|
||||
@@ -294,47 +302,47 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
noResultsText.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
if (backButton != null && searchTextbox != null)
|
||||
if (backButton == null || searchTextbox == null)
|
||||
return;
|
||||
|
||||
var clearButtonX = searchBounds.max.x + 0.2f;
|
||||
var clearButtonY = searchBounds.center.y;
|
||||
|
||||
var clearObj = Object.Instantiate(backButton.gameObject, transform);
|
||||
clearObj.name = "ClearSearchButton";
|
||||
clearObj.transform.localScale = new Vector3(0.35f, 0.35f, 1f);
|
||||
clearObj.transform.localPosition = new Vector3(clearButtonX, clearButtonY, -1f);
|
||||
|
||||
clearObj.GetComponent<CloseButtonConsoleBehaviour>()?.DestroyImmediate();
|
||||
clearObj.GetComponent<AspectPosition>()?.DestroyImmediate();
|
||||
|
||||
var clearSearchButton = clearObj.GetComponent<PassiveButton>();
|
||||
if (clearSearchButton == null)
|
||||
{
|
||||
var clearButtonX = searchBounds.max.x + 0.2f;
|
||||
var clearButtonY = searchBounds.center.y;
|
||||
|
||||
var clearObj = Instantiate(backButton.gameObject, transform);
|
||||
clearObj.name = "ClearSearchButton";
|
||||
clearObj.transform.localScale = new Vector3(0.35f, 0.35f, 1f);
|
||||
clearObj.transform.localPosition = new Vector3(clearButtonX, clearButtonY, -1f);
|
||||
|
||||
clearObj.GetComponent<CloseButtonConsoleBehaviour>()?.DestroyImmediate();
|
||||
clearObj.GetComponent<AspectPosition>()?.DestroyImmediate();
|
||||
|
||||
var clearSearchButton = clearObj.GetComponent<PassiveButton>();
|
||||
if (clearSearchButton != null)
|
||||
{
|
||||
if (wikiClickSound != null)
|
||||
{
|
||||
clearSearchButton.ClickSound = wikiClickSound;
|
||||
}
|
||||
|
||||
clearSearchButton.OnClick.RemoveAllListeners();
|
||||
clearSearchButton.OnClick = new Button.ButtonClickedEvent();
|
||||
clearSearchButton.OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
if (searchTextbox == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
searchTextbox.SetText(string.Empty);
|
||||
searchText = string.Empty;
|
||||
currentPage = 0;
|
||||
var list = ShowPage();
|
||||
RefreshControllerOverlay(list);
|
||||
}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (wikiClickSound != null)
|
||||
{
|
||||
clearSearchButton.ClickSound = wikiClickSound;
|
||||
}
|
||||
|
||||
clearSearchButton.OnClick.RemoveAllListeners();
|
||||
clearSearchButton.OnClick = new Button.ButtonClickedEvent();
|
||||
clearSearchButton.OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
if (searchTextbox == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
searchTextbox.SetText(string.Empty);
|
||||
searchText = string.Empty;
|
||||
currentPage = 0;
|
||||
var list = ShowPage();
|
||||
RefreshControllerOverlay(list);
|
||||
}));
|
||||
}
|
||||
|
||||
[HideFromIl2Cpp]
|
||||
private static Bounds CalcSpriteBoundsInParentSpace(Transform parent, GameObject root)
|
||||
{
|
||||
var first = true;
|
||||
@@ -342,7 +350,8 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
|
||||
foreach (var r in root.GetComponentsInChildren<SpriteRenderer>(true))
|
||||
{
|
||||
if (r == null || r.sprite == null) continue;
|
||||
if (r == null || r.sprite == null)
|
||||
continue;
|
||||
|
||||
var b = r.bounds;
|
||||
var c = b.center;
|
||||
@@ -372,10 +381,9 @@ public abstract class CustomPaginableMenu(IntPtr il2CppPtr) : CustomPhoneMenu<Cu
|
||||
/// Begins/opens the custom player menu. After registering panels, it will prepare the search, pages, and open the menu.
|
||||
/// </summary>
|
||||
/// <param name="registerEntryPanels">Function where all panels should be registered.</param>
|
||||
[HideFromIl2Cpp]
|
||||
protected void Begin(Action registerEntryPanels)
|
||||
{
|
||||
MinigameStubs.Begin(this, null);
|
||||
MinigameStubs.Begin(Component, null);
|
||||
|
||||
searchText = string.Empty;
|
||||
currentPage = 0;
|
||||
|
||||
+108
-56
@@ -1,5 +1,4 @@
|
||||
using AmongUs.GameOptions;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using Reactor.Utilities.Extensions;
|
||||
@@ -9,12 +8,26 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
#pragma warning disable S2365 // Properties should not make collection or array copies
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace MiraAPI.Hud;
|
||||
|
||||
/// <summary>
|
||||
/// Component registered in Il2Cpp domain to handle Unity events for custom menus.
|
||||
/// </summary>
|
||||
[RegisterInIl2Cpp]
|
||||
public class CustomPhoneMenuComponent(IntPtr cppPtr) : Minigame(cppPtr)
|
||||
{
|
||||
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity convention.")]
|
||||
private void OnDisable()
|
||||
{
|
||||
if (ControllerManager.Instance)
|
||||
{
|
||||
ControllerManager.Instance.CloseOverlayMenu(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines an entry in a <see cref="CustomPhoneMenu"/> with a Panel.
|
||||
/// </summary>
|
||||
@@ -53,14 +66,13 @@ public interface ICustomMenu<TMenu> : ICustomMenu where TMenu : IMenuEntry
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom Phone Menu using the <see cref="ShapeshifterPanel"/> as a base.
|
||||
/// Custom Phone Menu logic using the <see cref="ShapeshifterPanel"/> as a base.
|
||||
/// </summary>
|
||||
/// <param name="il2CppPtr">Used by Il2Cpp. Do not use constructor, this is a <see cref="MonoBehaviour"/>.</param>
|
||||
[RegisterInIl2Cpp]
|
||||
[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity Convention")]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Unity Convention")]
|
||||
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Unity Convention")]
|
||||
public abstract class CustomPhoneMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr), ICustomMenu
|
||||
[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity Convention.")]
|
||||
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Read above.")]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Read above.")]
|
||||
[SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Proxy for Unity properties.")]
|
||||
public abstract class CustomPhoneMenu : ICustomMenu
|
||||
{
|
||||
/// <summary>
|
||||
/// Menu Entry used when specifically only the Panel itself is required.
|
||||
@@ -68,14 +80,51 @@ public abstract class CustomPhoneMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr), I
|
||||
/// <param name="Panel">The <see cref="ShapeshifterPanel"/> instance.</param>
|
||||
protected sealed record class BasicEntry(ShapeshifterPanel Panel) : IMenuEntry
|
||||
{
|
||||
public static implicit operator ShapeshifterPanel(BasicEntry entry) => entry.Panel;
|
||||
/// <summary>
|
||||
/// Implicitly converts to <see cref="ShapeshifterPanel"/>.
|
||||
/// </summary>
|
||||
/// <param name="entry">The entry that contains the reference to the panel.</param>
|
||||
public static implicit operator ShapeshifterPanel(BasicEntry entry)
|
||||
{
|
||||
return entry.Panel;
|
||||
}
|
||||
|
||||
public static implicit operator BasicEntry(ShapeshifterPanel panel) => new(panel);
|
||||
/// <summary>
|
||||
/// Implicitly converts to an instance of <see cref="BasicEntry"/>.
|
||||
/// </summary>
|
||||
/// <param name="panel">The panel instance to make an entry off of.</param>
|
||||
public static implicit operator BasicEntry(ShapeshifterPanel panel)
|
||||
{
|
||||
return new(panel);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A delegate that is invoked when the mouse interacts with a panel.
|
||||
/// </summary>
|
||||
/// <param name="highlight">The panel's highlight that the delegate modifies.</param>
|
||||
/// <param name="icon">The panel's icon that the delegate modifies.</param>
|
||||
/// <param name="isSelected">A flag that indicates if the current panel is selected.</param>
|
||||
public delegate void PanelButtonOnMouse(SpriteRenderer highlight, SpriteRenderer icon, bool isSelected);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the wrapped component that the menu modifies.
|
||||
/// </summary>
|
||||
public CustomPhoneMenuComponent Component { get; internal set; } = null!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public List<IMenuEntry> MenuEntries { get; protected set; } = [];
|
||||
|
||||
public List<ShapeshifterPanel> EntryPanels => MenuEntries.Select(e => e.Panel).ToList();
|
||||
/// <summary>
|
||||
/// Gets all of the panels of the menu.
|
||||
/// </summary>
|
||||
public List<ShapeshifterPanel> EntryPanels => [.. MenuEntries.Select(e => e.Panel)];
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member (Justification: Unity convention.)
|
||||
#pragma warning disable S1104 // Fields should not have public accessibility (Justification: Read above.)
|
||||
public Transform transform => Component.transform;
|
||||
public GameObject gameObject => Component.gameObject;
|
||||
public string name => Component.name;
|
||||
|
||||
public float xStart = -0.8f;
|
||||
public float yStart = 2.15f;
|
||||
@@ -86,15 +135,29 @@ public abstract class CustomPhoneMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr), I
|
||||
public UiElement backButton;
|
||||
public UiElement defaultButtonSelected;
|
||||
|
||||
public Transform PhoneUI => transform.FindChild("PhoneUI");
|
||||
|
||||
public delegate void PanelButtonOnMouse(SpriteRenderer highlight, SpriteRenderer icon, bool isSelected);
|
||||
|
||||
protected PanelButtonOnMouse? onMouseOverAction;
|
||||
protected PanelButtonOnMouse? onMouseOutAction;
|
||||
#pragma warning restore S1104 // Fields should not have public accessibility
|
||||
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
/// <summary>
|
||||
/// Gets the transform of the menu's Phone UI.
|
||||
/// </summary>
|
||||
public Transform PhoneUI => transform.FindChild("PhoneUI");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the z-axis depth that the menu is instantiated at.
|
||||
/// </summary>
|
||||
protected virtual float MenuDepth => -50f;
|
||||
|
||||
/// <summary>
|
||||
/// Closes the menu.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
Component.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <typeparamref name="TMenu"/>.
|
||||
/// </summary>
|
||||
@@ -102,32 +165,32 @@ public abstract class CustomPhoneMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr), I
|
||||
/// <param name="onMouseOut">Function that can optionally be run when the mouse is moved outside a menu panel.</param>
|
||||
/// <param name="onMouseOver">Function that can optionally be run when the mouse is moved over a menu panel.</param>
|
||||
/// <returns>New <typeparamref name="TMenu"/> object.</returns>
|
||||
protected static TMenu Create<TMenu>(
|
||||
PanelButtonOnMouse? onMouseOut = null,
|
||||
PanelButtonOnMouse? onMouseOver = null
|
||||
) where TMenu : CustomPhoneMenu
|
||||
protected static TMenu Create<TMenu>(PanelButtonOnMouse? onMouseOut = null, PanelButtonOnMouse? onMouseOver = null) where TMenu : CustomPhoneMenu, new()
|
||||
{
|
||||
var shapeShifterRole = RoleManager.Instance.GetRole(RoleTypes.Shapeshifter);
|
||||
|
||||
var ogMenu = shapeShifterRole.TryCast<ShapeshifterRole>()!.ShapeshifterMenu;
|
||||
var newMenu = Instantiate(ogMenu);
|
||||
var customMenu = newMenu.gameObject.AddComponent<TMenu>();
|
||||
|
||||
customMenu.panelPrefab = newMenu.PanelPrefab;
|
||||
customMenu.xStart = newMenu.XStart;
|
||||
customMenu.yStart = newMenu.YStart;
|
||||
customMenu.xOffset = newMenu.XOffset;
|
||||
customMenu.yOffset = newMenu.YOffset;
|
||||
customMenu.defaultButtonSelected = newMenu.DefaultButtonSelected;
|
||||
customMenu.backButton = newMenu.BackButton;
|
||||
var newMenu = Object.Instantiate(ogMenu);
|
||||
var component = newMenu.gameObject.AddComponent<CustomPhoneMenuComponent>();
|
||||
var customMenu = new TMenu
|
||||
{
|
||||
Component = component,
|
||||
panelPrefab = newMenu.PanelPrefab,
|
||||
xStart = newMenu.XStart,
|
||||
yStart = newMenu.YStart,
|
||||
xOffset = newMenu.XOffset,
|
||||
yOffset = newMenu.YOffset,
|
||||
defaultButtonSelected = newMenu.DefaultButtonSelected,
|
||||
backButton = newMenu.BackButton,
|
||||
};
|
||||
|
||||
var back = customMenu.backButton.GetComponent<PassiveButton>();
|
||||
back.OnClick.RemoveAllListeners();
|
||||
back.OnClick.AddListener((UnityAction)customMenu.Close);
|
||||
|
||||
customMenu.CloseSound = newMenu.CloseSound;
|
||||
customMenu.logger = newMenu.logger;
|
||||
customMenu.OpenSound = newMenu.OpenSound;
|
||||
component.CloseSound = newMenu.CloseSound;
|
||||
component.logger = newMenu.logger;
|
||||
component.OpenSound = newMenu.OpenSound;
|
||||
|
||||
newMenu.DestroyImmediate();
|
||||
|
||||
@@ -140,20 +203,6 @@ public abstract class CustomPhoneMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr), I
|
||||
return customMenu;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
ControllerManager.Instance.CloseOverlayMenu(name);
|
||||
}
|
||||
|
||||
#pragma warning disable CS0809 // Obsolete member overrides non-obsolete member
|
||||
[Obsolete("Will always fail. Call or define another Begin method that calls MinigameStubs.Begin", true)]
|
||||
[SuppressMessage("Info Code Smell", "S1133:Deprecated code should be removed", Justification = "Overrides an unusable method.")]
|
||||
public override sealed void Begin(PlayerTask task)
|
||||
{
|
||||
throw new NotImplementedException("Use the other Begin method.");
|
||||
}
|
||||
#pragma warning restore CS0809 // Obsolete member overrides non-obsolete member
|
||||
|
||||
/// <summary>
|
||||
/// Register new menu panels given a set of entries.
|
||||
/// </summary>
|
||||
@@ -176,7 +225,7 @@ public abstract class CustomPhoneMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr), I
|
||||
var index = currentEntries + i;
|
||||
var entry = list[i];
|
||||
|
||||
var shapeshifterPanel = Instantiate(panelPrefab, transform);
|
||||
var shapeshifterPanel = Object.Instantiate(panelPrefab, transform);
|
||||
shapeshifterPanel.transform.localPosition = new Vector3(0f, 0f, -1f);
|
||||
entryPanelConfig(shapeshifterPanel, index, entry);
|
||||
|
||||
@@ -226,7 +275,10 @@ public abstract class CustomPhoneMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr), I
|
||||
/// </summary>
|
||||
/// <param name="entry">The <see cref="IMenuEntry"/> to check.</param>
|
||||
/// <returns><see langword="true"/> if the <paramref name="entry"/> is selected, else <see langword="false"/>.</returns>
|
||||
protected virtual bool IsEntrySelected(IMenuEntry entry) => false;
|
||||
protected virtual bool IsEntrySelected(IMenuEntry entry)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the icon, over color, and unselected color for a given entry.
|
||||
@@ -235,7 +287,6 @@ public abstract class CustomPhoneMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr), I
|
||||
/// <param name="sprite">The <see cref="Sprite"/> to use as the icon, if any.</param>
|
||||
/// <param name="overColor">The <see cref="Color"/> to use when hovering over an entry.</param>
|
||||
/// <param name="unselectedColor">The <see cref="Color"/> to use when not hovering over an entry.</param>
|
||||
[HideFromIl2Cpp]
|
||||
protected static void SetNameplateAppearance(
|
||||
IMenuEntry menuEntry, LoadableAsset<Sprite>? sprite, Color? overColor, Color? unselectedColor)
|
||||
{
|
||||
@@ -260,13 +311,14 @@ public abstract class CustomPhoneMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr), I
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="CustomPhoneMenu(IntPtr)"/>
|
||||
/// <inheritdoc cref="CustomPhoneMenu"/>
|
||||
/// <typeparam name="TMenu">The type of menu entries.</typeparam>
|
||||
public abstract class CustomPhoneMenu<TMenu>(IntPtr il2CppPtr) : CustomPhoneMenu(il2CppPtr), ICustomMenu<TMenu> where TMenu : IMenuEntry
|
||||
public abstract class CustomPhoneMenu<TMenu> : CustomPhoneMenu, ICustomMenu<TMenu> where TMenu : IMenuEntry
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public new List<TMenu> MenuEntries
|
||||
{
|
||||
get => base.MenuEntries.Cast<TMenu>().ToList();
|
||||
protected set => base.MenuEntries = value.Cast<IMenuEntry>().ToList();
|
||||
get => [.. base.MenuEntries.Cast<TMenu>()];
|
||||
protected set => base.MenuEntries = [.. value.Cast<IMenuEntry>()];
|
||||
}
|
||||
}
|
||||
@@ -2,25 +2,22 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using UnityEngine;
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
|
||||
namespace MiraAPI.Hud;
|
||||
|
||||
/// <summary>
|
||||
/// Custom Player Menu using the <see cref="ShapeshifterPanel"/> as a base.
|
||||
/// </summary>
|
||||
/// <param name="il2CppPtr">Used by Il2Cpp. Do not use constructor, this is a <see cref="MonoBehaviour"/>.</param>
|
||||
[RegisterInIl2Cpp]
|
||||
[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity Convention")]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Unity Convention")]
|
||||
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Unity Convention")]
|
||||
public class CustomPlayerMenu(IntPtr il2CppPtr) : CustomMultiSelectMenu<PlayerControl>(il2CppPtr)
|
||||
[SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "Unity Convention.")]
|
||||
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "Read above.")]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Read above.")]
|
||||
public class CustomPlayerMenu : CustomMultiSelectMenu<PlayerControl>
|
||||
{
|
||||
[SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Read above.")]
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
public List<ShapeshifterPanel> potentialVictims;
|
||||
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="CustomPlayerMenu"/>.
|
||||
@@ -37,7 +34,6 @@ public class CustomPlayerMenu(IntPtr il2CppPtr) : CustomMultiSelectMenu<PlayerCo
|
||||
/// <param name="playerMatch">Function to determine if player should show in the custom menu.</param>
|
||||
/// <param name="onClick"><see cref="PassiveButton.OnClick"/> action for player.</param>
|
||||
/// <param name="shouldConfirm">Whether the set of both selections should be confirmed manually.</param>
|
||||
[HideFromIl2Cpp]
|
||||
public void Begin(Func<PlayerControl, bool> playerMatch, Action<PlayerControl?> onClick, bool shouldConfirm = false)
|
||||
{
|
||||
Begin(PlayerControl.AllPlayerControls.ToArray().Where(playerMatch), onClick, shouldConfirm);
|
||||
@@ -51,7 +47,6 @@ public class CustomPlayerMenu(IntPtr il2CppPtr) : CustomMultiSelectMenu<PlayerCo
|
||||
/// <param name="onClick"><see cref="PassiveButton.OnClick"/> action for the two-player selection.</param>
|
||||
/// <param name="shouldConfirm">Whether the set of both selections should be confirmed manually.</param>
|
||||
/// <param name="canRepeat">If the same entry can be selected both times, else unselect entry on click.</param>
|
||||
[HideFromIl2Cpp]
|
||||
public void Begin(Func<PlayerControl, bool> playerMatch, Action<PlayerControl?, PlayerControl?> onClick, bool shouldConfirm = false, bool canRepeat = false)
|
||||
{
|
||||
Begin(PlayerControl.AllPlayerControls.ToArray().Where(playerMatch), onClick, shouldConfirm, canRepeat);
|
||||
|
||||
Reference in new issue
Block a user