using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using HarmonyLib; using Il2CppInterop.Runtime.Attributes; using MiraAPI.LocalSettings; using MiraAPI.Utilities.Assets; using Reactor.Utilities.Attributes; using Reactor.Utilities.Extensions; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; namespace MiraAPI.Modifiers.ModifierDisplay; /// /// The code used to display s. /// [RegisterInIl2Cpp] public class ModifierDisplayComponent(nint cppPtr) : MonoBehaviour(cppPtr) { /// /// Gets the instance of the . /// public static ModifierDisplayComponent? Instance { get; private set; } private RectTransform _children = null!; private GameObject _modTemplate = null!; private PassiveButton _toggleButton = null!; private TextMeshPro _toggleBtnText = null!; private RectTransform _pagination = null!; private TextMeshPro _pageText = null!; private PassiveButton _nextButton = null!; private PassiveButton _backButton = null!; private int _currentPage; private const int ItemsPerPage = 3; private readonly Dictionary _modifiers = []; /// /// Gets a of the created s. /// [HideFromIl2Cpp] public ReadOnlyDictionary Modifiers => new(_modifiers); /// /// Gets a value indicating whether the modifier display hud is currently open. /// public bool IsOpen { get; private set; } private void Awake() { Instance = this; _children = transform.GetChild(0).GetComponent(); _modTemplate = transform.GetChild(2).gameObject; _toggleButton = transform.GetChild(1).GetComponent(); _toggleButton.OnClick = new Button.ButtonClickedEvent(); _toggleButton.OnClick.AddListener((UnityAction)(() => { IsOpen = !IsOpen; _children.gameObject.SetActive(!_children.gameObject.activeSelf); })); _toggleButton.ClickSound = HudManager.Instance.GameMenu.StreamerModeButton.GetComponent().ClickSound; _toggleButton.HoverSound = HudManager.Instance.GameMenu.StreamerModeButton.GetComponent().HoverSound; _toggleButton.inactiveSprites = _toggleButton.transform.GetChild(1).gameObject; _toggleBtnText = _toggleButton.transform.GetChild(0).GetComponent(); _pagination = _children.transform.GetChild(0).GetComponent(); _pageText = _pagination.transform.GetChild(0).GetComponent(); _nextButton = _pagination.transform.GetChild(1).GetComponent(); _backButton = _pagination.transform.GetChild(2).GetComponent(); _toggleBtnText.font = _pageText.font = _nextButton.buttonText.font = _backButton.buttonText.font = HudManager.Instance.TaskPanel.taskText.font; _toggleBtnText.fontMaterial = _pageText.fontMaterial = _nextButton.buttonText.fontMaterial = _backButton.buttonText.fontMaterial = HudManager.Instance.TaskPanel.taskText.fontMaterial; _nextButton.OnClick = new Button.ButtonClickedEvent(); _nextButton.OnClick.AddListener((UnityAction)(() => { _currentPage++; UpdatePage(); })); _backButton.OnClick = new Button.ButtonClickedEvent(); _backButton.OnClick.AddListener((UnityAction)(() => { _currentPage--; UpdatePage(); })); IsOpen = false; _children.gameObject.SetActive(false); if (LocalSettingsTabSingleton.Instance.ModifiersHudLeftSide.Value) { var aspect = GetComponent(); _toggleButton.transform.localPosition = new Vector3(-1f, 2.7f, 0f); _children.transform.localPosition = new Vector3(-0.2f, -0.05f, 0f); aspect.Alignment = AspectPosition.EdgeAlignments.LeftTop; aspect.DistanceFromEdge = new Vector3(1.8f, 2.55f, -20f); aspect.AdjustPosition(); } } /// /// Use this to refresh the modifiers UI. Useful if you hide modifiers UIs based on options. /// public void RefreshModifiers() { UpdateModifiersList([.. PlayerControl.LocalPlayer.GetModifierComponent().ActiveModifiers]); } /// /// Use this to toggle the visibility of the modifiers tab. /// public void ToggleTab() { SetOpened(!IsOpen); } /// /// Use this to set the visibility of the modifiers tab. /// /// Whether it should be visible or not. public void SetOpened(bool val) { IsOpen = val; _children.gameObject.SetActive(IsOpen); RefreshModifiers(); } internal void DestroyComponent(ModifierUiComponent component) { _modifiers.Remove(component.Modifier!); component.gameObject.Destroy(); RefreshModifiers(); } [HideFromIl2Cpp] internal static ModifierDisplayComponent CreateDisplay() { var gameObject = Instantiate(MiraAssets.ModifierDisplay.LoadAsset(), HudManager.Instance.transform); var minigame = gameObject.AddComponent(); return minigame; } [HideFromIl2Cpp] private ModifierUiComponent CreateForModifier(BaseModifier modifier) { var newMod = Instantiate(_modTemplate, _children.transform); newMod.transform.name = modifier.ModifierName; var comp = newMod.AddComponent(); comp.Modifier = modifier; return comp; } private void UpdatePage() { var totalPages = Mathf.CeilToInt((float)_modifiers.Count / ItemsPerPage); _currentPage = Mathf.Clamp(_currentPage, 0, Mathf.Max(0, totalPages - 1)); if (_modifiers.Count <= ItemsPerPage) { _modifiers.Do(x => x.Value.gameObject.SetActive(true)); _pagination.gameObject.SetActive(false); return; } _pagination.gameObject.SetActive(true); if (_pageText != null) { _pageText.text = $"Page {_currentPage + 1}/{Mathf.Max(totalPages, 1)}"; } _nextButton.gameObject.SetActive(true); _backButton.gameObject.SetActive(true); _modifiers.Do(x => x.Value.gameObject.SetActive(false)); var start = _currentPage * ItemsPerPage; var end = Mathf.Min(start + ItemsPerPage, _modifiers.Count); var modifiers = _modifiers.ToArray(); for (var i = start; i < end; i++) { modifiers[i].Value.gameObject.SetActive(true); } _pagination.SetAsLastSibling(); } [HideFromIl2Cpp] internal void UpdateModifiersList(List modifiers) { var filteredModifiers = modifiers.Where(x => !x.HideOnUi && x.GetDescription() != string.Empty).ToList(); var modifiersToAdd = filteredModifiers.ToList(); foreach (var mod in _modifiers.ToArray()) { if (modifiersToAdd.Contains(mod.Key)) { modifiersToAdd.Remove(mod.Key); continue; } mod.Value.gameObject.Destroy(); _modifiers.Remove(mod.Key); } _toggleBtnText.text = $"Modifiers ({filteredModifiers.Count})"; _toggleButton.gameObject.SetActive(filteredModifiers.Count != 0); foreach (var mod in modifiersToAdd) { _modifiers.Add(mod, CreateForModifier(mod)); } UpdatePage(); } }