diff --git a/.editorconfig b/.editorconfig index af9feb4..2f48813 100644 --- a/.editorconfig +++ b/.editorconfig @@ -86,3 +86,15 @@ dotnet_diagnostic.SA1133.severity = none # IDE0001: Simplify Names dotnet_diagnostic.IDE0001.severity = warning + +# IDE0079: Remove unnecessary suppression +dotnet_diagnostic.IDE0079.severity = none + +# S3903: Types should be defined in named namespaces +dotnet_diagnostic.S3903.severity = none + +# IDE0045: Convert to conditional expression +dotnet_diagnostic.IDE0045.severity = none + +# IDE0046: Convert to conditional expression +dotnet_diagnostic.IDE0046.severity = none diff --git a/MiraAPI.Example/.editorconfig b/MiraAPI.Example/.editorconfig new file mode 100644 index 0000000..171e612 --- /dev/null +++ b/MiraAPI.Example/.editorconfig @@ -0,0 +1,4 @@ +[*.{cs,vb}] + +# SA1602: Enumeration items should be documented. +dotnet_diagnostic.SA1602.severity = none diff --git a/MiraAPI.Example/Resources/Locale/en_US.xml b/MiraAPI.Example/Resources/Locale/en_US.xml index e370dc3..56f74c8 100644 --- a/MiraAPI.Example/Resources/Locale/en_US.xml +++ b/MiraAPI.Example/Resources/Locale/en_US.xml @@ -16,11 +16,11 @@ Your votes have double the power. You get one extra vote in the meeting! The Mayor is a Crewmate role that gets two votes in the meeting, instead of the singular vote other Crewmates get. - Chamelon - Become one with the environment. - Fade out of everyone's vision by not moving. - Stay invisible while not moving. - The Chamelon is a Crewmate role that slowly becomes invisible while standing still. + Chameleon + Become one with the environment. + Fade out of everyone's vision by not moving. + Stay invisible while not moving. + The Chameleon is a Crewmate role that slowly becomes invisible while standing still. Outcast Killer Kill everyone else. Be the last outcast standing. @@ -73,7 +73,7 @@ Eliminate every other faction. Example Bool 2 Slider Example Number - Example Multplier + Example Multiplier Example Enum Example Button Outcast Killer Wins! diff --git a/MiraAPI/GameModes/HideAndSeekMode.cs b/MiraAPI/GameModes/HideAndSeekMode.cs index 316c3cf..ec99ce9 100644 --- a/MiraAPI/GameModes/HideAndSeekMode.cs +++ b/MiraAPI/GameModes/HideAndSeekMode.cs @@ -1,7 +1,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using AmongUs.Data; @@ -462,7 +461,6 @@ public class HideAndSeekMode : AbstractGameMode } /// - [SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Warning cascades into forcing the entire tree to be ternary operators.")] public override PlayerBodyTypes GetBodyType(PlayerControl player) { if (player == null || player.Data == null || player.Data.Role == null) diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedPlayerOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedPlayerOption.cs index 646de56..40cf0f8 100644 --- a/MiraAPI/GameOptions/OptionTypes/ModdedPlayerOption.cs +++ b/MiraAPI/GameOptions/OptionTypes/ModdedPlayerOption.cs @@ -43,7 +43,7 @@ public class ModdedPlayerOption : ModdedOption data.Title = StringName; data.Type = global::OptionTypes.Player; - Values = new(); + Values = []; AllowNone = allowNone; Value = DefaultValue; } diff --git a/MiraAPI/Hud/CustomPaginableMenu.cs b/MiraAPI/Hud/CustomPaginableMenu.cs index 27f7819..f24ccee 100644 --- a/MiraAPI/Hud/CustomPaginableMenu.cs +++ b/MiraAPI/Hud/CustomPaginableMenu.cs @@ -100,7 +100,6 @@ public abstract class CustomPaginableMenu : CustomPhoneMenu GetFilteredEntries() { var query = NormalizeForSearch(searchText); diff --git a/MiraAPI/MiraApiPlugin.cs b/MiraAPI/MiraApiPlugin.cs index 4da8968..a07c36d 100644 --- a/MiraAPI/MiraApiPlugin.cs +++ b/MiraAPI/MiraApiPlugin.cs @@ -64,11 +64,9 @@ public partial class MiraApiPlugin : BasePlugin, IMiraPlugin private static MiraPluginManager? PluginManager { get; set; } internal Harmony Harmony { get; } = new(Id); - public static ConfigEntry WikiSortingGroup { get; private set; } - - public static ConfigEntry WikiSortingMethod { get; private set; } - - public static ConfigEntry WikiSortingFilter { get; private set; } + internal static ConfigEntry WikiSortingGroup { get; private set; } + internal static ConfigEntry WikiSortingMethod { get; private set; } + internal static ConfigEntry WikiSortingFilter { get; private set; } /// public override void Load() diff --git a/MiraAPI/Patches/.editorconfig b/MiraAPI/Patches/.editorconfig index 2622fc7..a019ed9 100644 --- a/MiraAPI/Patches/.editorconfig +++ b/MiraAPI/Patches/.editorconfig @@ -12,5 +12,5 @@ dotnet_diagnostic.SA1611.severity = none # SA1615: Element return value should be documented. dotnet_diagnostic.SA1615.severity = none -# S125: Sections of code should not be commented out. -dotnet_diagnostic.S125.severity = none \ No newline at end of file +# SA1602: Enumeration items should be documented. +dotnet_diagnostic.SA1602.severity = none \ No newline at end of file diff --git a/MiraAPI/Patches/AmongUsClientSyncPatch.cs b/MiraAPI/Patches/AmongUsClientSyncPatch.cs index a8a3dfe..926004d 100644 --- a/MiraAPI/Patches/AmongUsClientSyncPatch.cs +++ b/MiraAPI/Patches/AmongUsClientSyncPatch.cs @@ -36,7 +36,7 @@ internal static class AmongUsClientSyncPatch GameModeOption.RpcSyncGamemode(PlayerControl.LocalPlayer, GameModeOption.Value); } - [HarmonyPostfix] + [HarmonyPrefix] [HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.OnPlayerLeft))] public static void PlayerLeftPatch(ClientData data, DisconnectReasons reason) { diff --git a/MiraAPI/Patches/Menu/HatsTabPatches.cs b/MiraAPI/Patches/Menu/HatsTabPatches.cs deleted file mode 100644 index e9cebd8..0000000 --- a/MiraAPI/Patches/Menu/HatsTabPatches.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using AmongUs.Data; -using HarmonyLib; -using MiraAPI.Utilities; -using MiraAPI.Utilities.Assets; -using Reactor.Utilities; -using Reactor.Utilities.Extensions; -using TMPro; -using UnityEngine; -using Object = UnityEngine.Object; - -namespace MiraAPI.Patches.Menu; - -[HarmonyPatch(typeof(HatsTab))] -public static class HatsTabPatches -{ - private static readonly Dictionary StoreNames = []; - private static SortedList> sortedHats = []; - private static int currentPage; - - private static void PreviousPage(HatsTab hatsTab) - { - currentPage--; - currentPage = currentPage < 0 ? sortedHats.Count - 1 : currentPage; - GenerateHats(hatsTab, currentPage); - } - - private static void NextPage(HatsTab hatsTab) - { - currentPage++; - currentPage = currentPage > sortedHats.Count - 1 ? 0 : currentPage; - GenerateHats(hatsTab, currentPage); - } - - [HarmonyPatch(nameof(HatsTab.OnEnable))] - [HarmonyPrefix] - [SuppressMessage("Style", "IDE0028:Collection initialization can be simplified", Justification = "Preview feature.")] - public static bool OnEnablePrefix(HatsTab __instance) - { - if (!AddressablesLoader.AddressableHatsExist) - { - return true; - } - - __instance.currentHat = HatManager.Instance.GetHatById(DataManager.Player.Customization.Hat); - var allHats = HatManager.Instance.GetUnlockedHats().ToImmutableList(); - - if (sortedHats.Count == 0) - { - var num = 0; - var comparer = new ControllableComparer(["vanilla"], [], StringComparer.InvariantCulture); - sortedHats = new SortedList>(comparer); - foreach (var hat in allHats) - { - if (!sortedHats.ContainsKey(hat.StoreName)) sortedHats[hat.StoreName] = []; - sortedHats[hat.StoreName].Add(hat); - - if (!StoreNames.ContainsValue(hat.StoreName)) - { - StoreNames.Add(num, hat.StoreName); - num++; - } - } - } - - InventoryUtility.CreateNextBackButtons(__instance, PreviousPage, NextPage); - - GenerateHats(__instance, currentPage); - - return false; - } - - [HarmonyPatch(typeof(HatsTab), nameof(HatsTab.Update))] - [HarmonyPrefix] - public static void UpdatePrefix(HatsTab __instance) - { - if (!AddressablesLoader.AddressableHatsExist) - { - return; - } - - if (sortedHats.Count == 0) return; - - if (Input.GetKeyDown(KeyCode.LeftControl) || Input.GetKeyDown(KeyCode.RightControl) || Input.GetKeyDown(KeyCode.LeftArrow)) - { - PreviousPage(__instance); - } - else if (Input.GetKeyDown(KeyCode.Tab) || Input.GetKeyDown(KeyCode.RightArrow)) - { - NextPage(__instance); - } - } - - private static IEnumerator? loadRoutine; - private static int hatIndex; - - private static void GenerateHats(HatsTab __instance, int page) - { - if (loadRoutine != null) Coroutines.Stop(loadRoutine); - - hatIndex = 0; - foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy(); - __instance.ColorChips.Clear(); - __instance.scroller.Inner.GetComponentsInChildren().Do(x => x.gameObject.DeepDestroy(false)); - - var groupNameText = __instance.GetComponentInChildren(false); - var group = sortedHats.Where(x => x.Key == StoreNames[page]); - - foreach (var (groupName, hats) in group) - { - var text = Object.Instantiate(groupNameText, __instance.scroller.Inner); - text.enabled = true; - text.gameObject.transform.localScale = Vector3.one; - text.GetComponent().Destroy(); - text.EnableStencilMasking(); - text.text = $"{groupName} ({currentPage + 1}/{sortedHats.Count})"; - text.alignment = TextAlignmentOptions.Center; - text.fontSize = 5f; - text.fontSizeMax = 5f; - text.fontSizeMin = 0f; - var xLerp = __instance.XRange.Lerp(0.5f); - - // ReSharper disable once PossibleLossOfFraction (Justification: Intended.) - var yLerp = __instance.YStart - hatIndex / __instance.NumPerRow * __instance.YOffset; - text.transform.localPosition = new Vector3(xLerp, yLerp, -1f); - - hatIndex += 5; - loadRoutine = Coroutines.Start(CoGenerateChips(__instance, hats)); - } - - // ReSharper disable once PossibleLossOfFraction (Justification: Intended.) - __instance.scroller.ContentYBounds.max = -(__instance.YStart - (hatIndex + 1) / __instance.NumPerRow * __instance.YOffset) - 3f; - __instance.currentHatIsEquipped = true; - } - - private static IEnumerator CoGenerateChips(HatsTab __instance, List hats) - { - __instance.scroller.ScrollToTop(); - var batchSize = 5; - for (var i = 0; i < hats.Count; i += batchSize) - { - var batch = hats.Skip(i).Take(batchSize).ToList(); - - foreach (var hat in batch.OrderBy(HatManager.Instance.allHats.IndexOf)) - { - var hatXPosition = __instance.XRange.Lerp(hatIndex % __instance.NumPerRow / (__instance.NumPerRow - 1f)); - - // ReSharper disable once PossibleLossOfFraction (Justification: Intended.) - var hatYPosition = __instance.YStart - hatIndex / __instance.NumPerRow * __instance.YOffset; - GenerateColorChip(__instance, new Vector2(hatXPosition, hatYPosition), hat); - hatIndex += 1; - yield return null; - } - - __instance.SetScrollerBounds(); - yield return new WaitForSeconds(0.01f); - } - - __instance.currentHatIsEquipped = true; - loadRoutine = null; - } - - private static void GenerateColorChip(HatsTab __instance, Vector2 position, HatData hat) - { - var colorChip = Object.Instantiate(__instance.ColorTabPrefab, __instance.scroller.Inner); - colorChip.gameObject.name = hat.ProductId; - if (ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard) - { - colorChip.Button.OnClick.AddListener((Action)__instance.ClickEquip); - colorChip.Button.OnMouseOver.AddListener((Action)(() => __instance.SelectHat(hat))); - colorChip.Button.OnMouseOut.AddListener((Action)(() => __instance.SelectHat(HatManager.Instance.GetHatById(DataManager.Player.Customization.Hat)))); - } - else - { - colorChip.Button.OnClick.AddListener((Action)(() => __instance.SelectHat(hat))); - } - - colorChip.Inner.SetHat(hat, __instance.HasLocalPlayer() ? PlayerControl.LocalPlayer.Data.DefaultOutfit.ColorId : DataManager.Player.Customization.Color); - colorChip.Button.ClickMask = __instance.scroller.Hitbox; - colorChip.SelectionHighlight.gameObject.SetActive(false); - __instance.UpdateMaterials(colorChip.Inner.FrontLayer, hat); - colorChip.Inner.SetMaskType(PlayerMaterial.MaskType.SimpleUI); - colorChip.transform.localPosition = new Vector3(position.x, position.y, -1f); - colorChip.Inner.transform.localPosition = hat.ChipOffset + new Vector2(0f, -0.3f); - colorChip.Tag = hat; - __instance.ColorChips.Add(colorChip); - } -} diff --git a/MiraAPI/Patches/Menu/InventoryUtility.cs b/MiraAPI/Patches/Menu/InventoryUtility.cs deleted file mode 100644 index 8284005..0000000 --- a/MiraAPI/Patches/Menu/InventoryUtility.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using MiraAPI.Utilities.Assets; -using TMPro; -using UnityEngine; -using UnityEngine.Events; -using UnityEngine.UI; -using Object = UnityEngine.Object; - -namespace MiraAPI.Patches.Menu; - -public static class InventoryUtility -{ - public static void CreateNextBackButtons(T tab, Action previousPage, Action nextPage) - where T : InventoryTab - { - var title = tab.transform.FindChild("Text"); - title.localPosition = new Vector3(.9123f, -.23f, -55); - title.GetComponent().alignment = TextAlignmentOptions.Center; - - tab.scroller.Hitbox.transform.localScale -= new Vector3(0, 0.1f, 0); - tab.scroller.Hitbox.transform.localPosition -= new Vector3(0, 0.1f, 0); - - var leftButtonElement = Object.Instantiate(PlayerCustomizationMenu.Instance.BackButton.gameObject, tab.transform); - var leftSpriteRenderer = leftButtonElement.GetComponent(); - var leftButton = leftButtonElement.GetComponent(); - - leftButtonElement.transform.localPosition = new Vector3(-1.1f, -0.2f, -55); - leftSpriteRenderer.sprite = MiraAssets.NextButton.LoadAsset(); - leftSpriteRenderer.flipX = true; - - leftButton.OnMouseOver = new UnityEvent(); - leftButton.OnMouseOver.AddListener((Action)(() => leftSpriteRenderer.sprite = MiraAssets.NextButtonActive.LoadAsset())); - leftButton.OnMouseOut = new UnityEvent(); - leftButton.OnMouseOut.AddListener((Action)(() => leftSpriteRenderer.sprite = MiraAssets.NextButton.LoadAsset())); - - leftButton.OnClick = new Button.ButtonClickedEvent(); - leftButton.OnClick.AddListener((Action)(() => previousPage(tab))); - - var rightButtonElement = Object.Instantiate(leftButtonElement, tab.transform); - var rightSpriteRenderer = rightButtonElement.GetComponent(); - var rightButton = rightButtonElement.GetComponent(); - - rightButtonElement.transform.localPosition = new Vector3(2.8f, -0.2f, -55); - rightSpriteRenderer.sprite = MiraAssets.NextButton.LoadAsset(); - rightSpriteRenderer.flipX = false; - - rightButton.OnMouseOver = new UnityEvent(); - rightButton.OnMouseOver.AddListener((Action)(() => rightSpriteRenderer.sprite = MiraAssets.NextButtonActive.LoadAsset())); - rightButton.OnMouseOut = new UnityEvent(); - rightButton.OnMouseOut.AddListener((Action)(() => rightSpriteRenderer.sprite = MiraAssets.NextButton.LoadAsset())); - - rightButton.OnClick = new Button.ButtonClickedEvent(); - rightButton.OnClick.AddListener((Action)(() => nextPage(tab))); - } -} diff --git a/MiraAPI/Patches/Menu/MainMenuManagerPatches.cs b/MiraAPI/Patches/Menu/MainMenuManagerPatches.cs index 4ac5b37..aff0906 100644 --- a/MiraAPI/Patches/Menu/MainMenuManagerPatches.cs +++ b/MiraAPI/Patches/Menu/MainMenuManagerPatches.cs @@ -2,7 +2,6 @@ using System.Collections; using HarmonyLib; using MiraAPI.LocalSettings; -using MiraAPI.Utilities.Assets; using Reactor.Utilities; using UnityEngine; @@ -23,10 +22,9 @@ public static class MainMenuManagerPatches [HarmonyPostfix] public static void AwakePostfix() { - var requiredVersion = new Version(2026, 6, 5); + var requiredVersion = new Version(2026, 9, 29); var version = Version.Parse(Application.version); NeedsDeepDestroy = version >= requiredVersion; - AddressablesLoader.LoadAll(); Coroutines.Start(SetFps()); } diff --git a/MiraAPI/Patches/Menu/NameplatesTabPatches.cs b/MiraAPI/Patches/Menu/NameplatesTabPatches.cs deleted file mode 100644 index c105eb1..0000000 --- a/MiraAPI/Patches/Menu/NameplatesTabPatches.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using AmongUs.Data; -using HarmonyLib; -using Innersloth.Assets; -using MiraAPI.Utilities; -using MiraAPI.Utilities.Assets; -using Reactor.Utilities.Extensions; -using TMPro; -using UnityEngine; -using Object = UnityEngine.Object; - -namespace MiraAPI.Patches.Menu; - -[HarmonyPatch(typeof(NameplatesTab))] -public static class NameplatesTabPatches -{ - [SuppressMessage("Style", "IDE0028:Collection initialization can be simplified", Justification = "Preview feature.")] - private static readonly SortedList> SortedNameplates = new(new ControllableComparer(["vanilla"], [], StringComparer.InvariantCulture)); - private static int currentPage; - - internal static void AddRange(IEnumerable<(string Key, NamePlateData Visor)> data) - { - foreach (var (key, visor) in data) - { - if (!SortedNameplates.ContainsKey(key)) SortedNameplates.Add(key, []); - SortedNameplates[key].Add(visor); - } - } - - private static void PreviousPage(NameplatesTab tab) - { - currentPage--; - currentPage = currentPage < 0 ? SortedNameplates.Count - 1 : currentPage; - GenerateHats(tab, currentPage); - } - - private static void NextPage(NameplatesTab tab) - { - currentPage++; - currentPage = currentPage > SortedNameplates.Count - 1 ? 0 : currentPage; - GenerateHats(tab, currentPage); - } - - [HarmonyPatch(nameof(NameplatesTab.OnEnable))] - [HarmonyPrefix] - public static bool OnEnablePrefix(NameplatesTab __instance) - { - if (!AddressablesLoader.AddressableNameplatesExist) - { - return true; - } - - __instance.plateId = HatManager.Instance.GetNamePlateById(DataManager.Player.Customization.namePlate).ProdId; - - if (!SortedNameplates.ContainsKey("Vanilla")) AddRange(HatManager.Instance.GetUnlockedNamePlates().Select(x => ("Vanilla", x))); - - InventoryUtility.CreateNextBackButtons(__instance, PreviousPage, NextPage); - - GenerateHats(__instance, currentPage); - - return false; - } - - [HarmonyPatch(typeof(NameplatesTab), nameof(NameplatesTab.Update))] - [HarmonyPrefix] - - public static void UpdatePrefix(NameplatesTab __instance) - { - if (!AddressablesLoader.AddressableNameplatesExist) - { - return; - } - - if (Input.GetKeyDown(KeyCode.LeftControl) || Input.GetKeyDown(KeyCode.RightControl) || Input.GetKeyDown(KeyCode.LeftArrow)) - { - PreviousPage(__instance); - } - else if (Input.GetKeyDown(KeyCode.Tab) || Input.GetKeyDown(KeyCode.RightArrow)) - { - NextPage(__instance); - } - } - - private static void GenerateHats(NameplatesTab __instance, int page) - { - foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy(); - __instance.ColorChips.Clear(); - __instance.scroller.Inner.GetComponentsInChildren().Do(x => x.gameObject.DeepDestroy(false)); - - var groupNameText = __instance.GetComponentInChildren(false); - - var hatIndex = 0; - - var (groupName, nameplates) = SortedNameplates.ToArray()[page]; - var text = Object.Instantiate(groupNameText, __instance.scroller.Inner); - text.enabled = true; - text.gameObject.transform.localScale = Vector3.one; - text.GetComponent().Destroy(); - text.EnableStencilMasking(); - text.text = $"{groupName} ({currentPage + 1}/{SortedNameplates.Count})"; - text.alignment = TextAlignmentOptions.Center; - text.fontSize = 5f; - text.fontSizeMax = 5f; - text.fontSizeMin = 0f; - var xLerp = __instance.XRange.Lerp(0.5f); - var yLerp = __instance.YStart - __instance.YOffset; - text.transform.localPosition = new Vector3(xLerp, yLerp, -1f); - - hatIndex += 2; - foreach (var visor in nameplates.OrderBy(HatManager.Instance.allNamePlates.IndexOf)) - { - var hatXPosition = __instance.XRange.Lerp(hatIndex % __instance.NumPerRow / (__instance.NumPerRow - 1f)); - - // ReSharper disable once PossibleLossOfFraction (Justification: Intended.) - var hatYPosition = __instance.YStart - hatIndex / __instance.NumPerRow * __instance.YOffset; - GenerateColorChip(__instance, new Vector2(hatXPosition, hatYPosition), visor); - hatIndex += 1; - } - - __instance.SetScrollerBounds(); - __instance.currentNameplateIsEquipped = true; - } - - private static void GenerateColorChip(NameplatesTab __instance, Vector2 position, NamePlateData namePlate) - { - var colorChip = Object.Instantiate(__instance.ColorTabPrefab, __instance.scroller.Inner); - colorChip.gameObject.name = namePlate.ProductId; - - if (ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard) - { - colorChip.Button.OnClick.AddListener((Action)__instance.ClickEquip); - colorChip.Button.OnMouseOver.AddListener((Action)(() => __instance.SelectNameplate(namePlate))); - colorChip.Button.OnMouseOut.AddListener( - (Action)(() => __instance.SelectNameplate( - HatManager.Instance.GetNamePlateById(DataManager.Player.Customization.NamePlate)))); - } - else - { - colorChip.Button.OnClick.AddListener((Action)(() => __instance.SelectNameplate(namePlate))); - } - - colorChip.Button.ClickMask = __instance.scroller.Hitbox; - colorChip.ProductId = namePlate.ProdId; - - __instance.StartCoroutine(__instance.CoLoadAssetAsync(namePlate.GetAssetReference(), (Action?)LoadNameplate)); - colorChip.transform.localPosition = new Vector3(position.x, position.y, -1f); - colorChip.Tag = namePlate; - __instance.ColorChips.Add(colorChip); - return; - - void LoadNameplate(NamePlateViewData viewData) - { - colorChip.transform.GetChild(1).GetComponent().sprite = viewData.Image; - - // (colorChip as NameplateChip).image.sprite = viewData?.Image; - } - } -} diff --git a/MiraAPI/Patches/Menu/SkinsTabPatches.cs b/MiraAPI/Patches/Menu/SkinsTabPatches.cs deleted file mode 100644 index 08bfe8c..0000000 --- a/MiraAPI/Patches/Menu/SkinsTabPatches.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using AmongUs.Data; -using HarmonyLib; -using MiraAPI.Utilities; -using MiraAPI.Utilities.Assets; -using Reactor.Utilities.Extensions; -using TMPro; -using UnityEngine; -using Object = UnityEngine.Object; - -namespace MiraAPI.Patches.Menu; - -[HarmonyPatch(typeof(SkinsTab))] -public static class SkinsTabPatches -{ - private static SortedList> sortedSkins = []; - private static int currentPage; - - private static void PreviousPage(SkinsTab tab) - { - currentPage--; - currentPage = currentPage < 0 ? sortedSkins.Count - 1 : currentPage; - GenerateHats(tab, currentPage); - } - - private static void NextPage(SkinsTab tab) - { - currentPage++; - currentPage = currentPage > sortedSkins.Count - 1 ? 0 : currentPage; - GenerateHats(tab, currentPage); - } - - [HarmonyPatch(nameof(SkinsTab.OnEnable))] - [HarmonyPrefix] - [SuppressMessage("Style", "IDE0028:Collection initialization can be simplified", Justification = "Preview feature.")] - public static bool OnEnablePrefix(SkinsTab __instance) - { - if (!AddressablesLoader.AddressableSkinsExist) - { - return true; - } - - __instance.skinId = HatManager.Instance.GetSkinById(DataManager.Player.Customization.Skin).ProdId; - var allSkins = HatManager.Instance.GetUnlockedSkins().ToImmutableList(); - - if (sortedSkins.Count == 0) - { - var comparer = new ControllableComparer(["vanilla"], [], StringComparer.InvariantCulture); - sortedSkins = new SortedList>(comparer); - foreach (var skin in allSkins) - { - if (!sortedSkins.ContainsKey(skin.StoreName)) sortedSkins[skin.StoreName] = []; - sortedSkins[skin.StoreName].Add(skin); - } - } - - InventoryUtility.CreateNextBackButtons(__instance, PreviousPage, NextPage); - - GenerateHats(__instance, currentPage); - - return false; - } - - [HarmonyPatch(typeof(SkinsTab), nameof(SkinsTab.Update))] - [HarmonyPrefix] - - public static void UpdatePrefix(SkinsTab __instance) - { - if (!AddressablesLoader.AddressableSkinsExist) - { - return; - } - - if (Input.GetKeyDown(KeyCode.LeftControl) || Input.GetKeyDown(KeyCode.RightControl) || Input.GetKeyDown(KeyCode.LeftArrow)) - { - PreviousPage(__instance); - } - else if (Input.GetKeyDown(KeyCode.Tab) || Input.GetKeyDown(KeyCode.RightArrow)) - { - NextPage(__instance); - } - } - - private static void GenerateHats(SkinsTab __instance, int page) - { - foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy(); - __instance.ColorChips.Clear(); - __instance.scroller.Inner.GetComponentsInChildren().Do(x => x.gameObject.DeepDestroy(false)); - - var groupNameText = __instance.GetComponentInChildren(false); - - var hatIndex = 0; - - var (groupName, skins) = sortedSkins.ToArray()[page]; - var text = Object.Instantiate(groupNameText, __instance.scroller.Inner); - text.enabled = true; - text.gameObject.transform.localScale = Vector3.one; - text.GetComponent().Destroy(); - text.EnableStencilMasking(); - text.text = $"{groupName} ({currentPage + 1}/{sortedSkins.Count})"; - text.alignment = TextAlignmentOptions.Center; - text.fontSize = 5f; - text.fontSizeMax = 5f; - text.fontSizeMin = 0f; - var xLerp = __instance.XRange.Lerp(0.5f); - var yLerp = __instance.YStart - __instance.YOffset; - text.transform.localPosition = new Vector3(xLerp, yLerp, -1f); - - hatIndex += 5; - foreach (var skin in skins.OrderBy(HatManager.Instance.allSkins.IndexOf)) - { - var hatXPosition = __instance.XRange.Lerp(hatIndex % __instance.NumPerRow / (__instance.NumPerRow - 1f)); - - // ReSharper disable once PossibleLossOfFraction (Justification: Intended.) - var hatYPosition = __instance.YStart - hatIndex / __instance.NumPerRow * __instance.YOffset; - GenerateColorChip(__instance, new Vector2(hatXPosition, hatYPosition), skin); - hatIndex += 1; - } - - __instance.SetScrollerBounds(); - __instance.currentSkinIsEquipped = true; - } - - private static void GenerateColorChip(SkinsTab __instance, Vector2 position, SkinData skin) - { - var colorChip = Object.Instantiate(__instance.ColorTabPrefab, __instance.scroller.Inner); - colorChip.gameObject.name = skin.ProductId; - if (ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard) - { - colorChip.Button.OnClick.AddListener((Action)__instance.ClickEquip); - colorChip.Button.OnMouseOver.AddListener((Action)(() => __instance.SelectSkin(skin))); - colorChip.Button.OnMouseOut.AddListener( - (Action)(() => - __instance.SelectSkin(HatManager.Instance.GetSkinById(DataManager.Player.Customization.Skin)))); - } - else - { - colorChip.Button.OnClick.AddListener((Action)(() => __instance.SelectSkin(skin))); - } - - colorChip.Button.ClickMask = __instance.scroller.Hitbox; - colorChip.ProductId = skin.ProductId; - colorChip.SelectionHighlight.gameObject.SetActive(false); - __instance.UpdateMaterials(colorChip.Inner.FrontLayer, skin); - skin.SetPreview(colorChip.Inner.FrontLayer, __instance.HasLocalPlayer() ? PlayerControl.LocalPlayer.Data.DefaultOutfit.ColorId : DataManager.Player.Customization.Color); - colorChip.transform.localPosition = new Vector3(position.x, position.y, -1f); - colorChip.Inner.transform.localPosition = skin.ChipOffset + new Vector2(0f, -0.3f); - colorChip.Tag = skin; - __instance.ColorChips.Add(colorChip); - } -} diff --git a/MiraAPI/Patches/Menu/VisorsTabPatches.cs b/MiraAPI/Patches/Menu/VisorsTabPatches.cs deleted file mode 100644 index cc37c28..0000000 --- a/MiraAPI/Patches/Menu/VisorsTabPatches.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using AmongUs.Data; -using HarmonyLib; -using MiraAPI.Utilities; -using MiraAPI.Utilities.Assets; -using Reactor.Utilities.Extensions; -using TMPro; -using UnityEngine; -using Object = UnityEngine.Object; - -namespace MiraAPI.Patches.Menu; - -[HarmonyPatch(typeof(VisorsTab))] -public static class VisorsTabPatches -{ - [SuppressMessage("Style", "IDE0028:Collection initialization can be simplified", Justification = "Preview feature.")] - private static readonly SortedList> SortedVisors = new(new ControllableComparer(["vanilla"], [], StringComparer.InvariantCulture)); - private static int currentPage; - - internal static void AddRange(IEnumerable<(string Key, VisorData Visor)> data) - { - foreach (var (key, visor) in data) - { - if (!SortedVisors.ContainsKey(key)) SortedVisors.Add(key, []); - SortedVisors[key].Add(visor); - } - } - - private static void PreviousPage(VisorsTab tab) - { - currentPage--; - currentPage = currentPage < 0 ? SortedVisors.Count - 1 : currentPage; - GenerateHats(tab, currentPage); - } - - private static void NextPage(VisorsTab tab) - { - currentPage++; - currentPage = currentPage > SortedVisors.Count - 1 ? 0 : currentPage; - GenerateHats(tab, currentPage); - } - - [HarmonyPatch(nameof(VisorsTab.OnEnable))] - [HarmonyPrefix] - public static bool OnEnablePrefix(VisorsTab __instance) - { - if (!AddressablesLoader.AddressableVisorsExist) - { - return true; - } - - __instance.visorId = HatManager.Instance.GetVisorById(DataManager.Player.Customization.Visor).ProdId; - - if (!SortedVisors.ContainsKey("Vanilla")) AddRange(HatManager.Instance.GetUnlockedVisors().Select(x => ("Vanilla", x))); - - InventoryUtility.CreateNextBackButtons(__instance, PreviousPage, NextPage); - - GenerateHats(__instance, currentPage); - - return false; - } - - [HarmonyPatch(typeof(VisorsTab), nameof(VisorsTab.Update))] - [HarmonyPrefix] - - public static void UpdatePrefix(VisorsTab __instance) - { - if (!AddressablesLoader.AddressableVisorsExist) - { - return; - } - - if (Input.GetKeyDown(KeyCode.LeftControl) || Input.GetKeyDown(KeyCode.RightControl) || Input.GetKeyDown(KeyCode.LeftArrow)) - { - PreviousPage(__instance); - } - else if (Input.GetKeyDown(KeyCode.Tab) || Input.GetKeyDown(KeyCode.RightArrow)) - { - NextPage(__instance); - } - } - - private static void GenerateHats(VisorsTab __instance, int page) - { - foreach (var instanceColorChip in __instance.ColorChips) instanceColorChip.gameObject.Destroy(); - __instance.ColorChips.Clear(); - __instance.scroller.Inner.GetComponentsInChildren().Do(x => x.gameObject.DeepDestroy(false)); - - var groupNameText = __instance.GetComponentInChildren(false); - - var hatIndex = 0; - - var (groupName, visors) = SortedVisors.ToArray()[page]; - var text = Object.Instantiate(groupNameText, __instance.scroller.Inner); - text.enabled = true; - text.gameObject.transform.localScale = Vector3.one; - text.GetComponent().Destroy(); - text.EnableStencilMasking(); - text.text = $"{groupName} ({currentPage + 1}/{SortedVisors.Count})"; - text.alignment = TextAlignmentOptions.Center; - text.fontSize = 5f; - text.fontSizeMax = 5f; - text.fontSizeMin = 0f; - var xLerp = __instance.XRange.Lerp(0.5f); - var yLerp = __instance.YStart - __instance.YOffset; - text.transform.localPosition = new Vector3(xLerp, yLerp, -1f); - - hatIndex += 5; - foreach (var visor in visors.OrderBy(HatManager.Instance.allVisors.IndexOf)) - { - var hatXPosition = __instance.XRange.Lerp(hatIndex % __instance.NumPerRow / (__instance.NumPerRow - 1f)); - - // ReSharper disable once PossibleLossOfFraction (Justification: Intended.) - var hatYPosition = __instance.YStart - hatIndex / __instance.NumPerRow * __instance.YOffset; - GenerateColorChip(__instance, new Vector2(hatXPosition, hatYPosition), visor); - hatIndex += 1; - } - - __instance.SetScrollerBounds(); - __instance.currentVisorIsEquipped = true; - } - - private static void GenerateColorChip(VisorsTab __instance, Vector2 position, VisorData visor) - { - var colorChip = Object.Instantiate(__instance.ColorTabPrefab, __instance.scroller.Inner); - colorChip.gameObject.name = visor.ProductId; - - if (ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard) - { - colorChip.Button.OnClick.AddListener((Action)__instance.ClickEquip); - colorChip.Button.OnMouseOver.AddListener((Action)(() => __instance.SelectVisor(visor))); - colorChip.Button.OnMouseOut.AddListener( - (Action)(() => - __instance.SelectVisor(HatManager.Instance.GetVisorById(DataManager.Player.Customization.Visor)))); - } - else - { - colorChip.Button.OnClick.AddListener((Action)(() => __instance.SelectVisor(visor))); - } - - colorChip.Button.ClickMask = __instance.scroller.Hitbox; - colorChip.ProductId = visor.ProductId; - colorChip.SelectionHighlight.gameObject.SetActive(false); - __instance.UpdateMaterials(colorChip.Inner.FrontLayer, visor); - visor.SetPreview(colorChip.Inner.FrontLayer, __instance.HasLocalPlayer() ? PlayerControl.LocalPlayer.Data.DefaultOutfit.ColorId : DataManager.Player.Customization.Color); - colorChip.transform.localPosition = new Vector3(position.x, position.y, -1f); - colorChip.Inner.transform.localPosition = visor.ChipOffset + new Vector2(0f, -0.3f); - colorChip.Tag = visor; - __instance.ColorChips.Add(colorChip); - } -} diff --git a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs index ecf574c..69966d4 100644 --- a/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs +++ b/MiraAPI/Patches/Options/GameOptionsMenuPatch.cs @@ -25,9 +25,9 @@ namespace MiraAPI.Patches.Options; [HarmonyPatch(typeof(GameOptionsMenu))] internal static class GameOptionsMenuPatch { - private static readonly List VanillaHeaders = new(); - private static readonly List VanillaOptions = new(); - private static readonly List MainOptions = new(); + private static readonly List VanillaHeaders = []; + private static readonly List VanillaOptions = []; + private static readonly List MainOptions = []; private static readonly Dictionary> GameModeGroups = []; private static readonly Dictionary> GameModeOptions = []; private static readonly Dictionary> GameModeHeaders = []; diff --git a/MiraAPI/Patches/Options/OptionsPatches.cs b/MiraAPI/Patches/Options/OptionsPatches.cs index 0b7f5b9..670a782 100644 --- a/MiraAPI/Patches/Options/OptionsPatches.cs +++ b/MiraAPI/Patches/Options/OptionsPatches.cs @@ -32,6 +32,11 @@ public static class OptionsPatches __instance.roleChance = 0; } + if (__instance.roleChance == 0) + { + __instance.roleMaxCount = 0; + } + __instance.OnValueChanged.Invoke(__instance); return false; } @@ -58,6 +63,11 @@ public static class OptionsPatches __instance.roleChance = 100; } + if (__instance.roleChance == 0) + { + __instance.roleMaxCount = 0; + } + __instance.OnValueChanged.Invoke(__instance); return false; } @@ -82,6 +92,11 @@ public static class OptionsPatches __instance.roleMaxCount = 0; } + if (__instance.roleMaxCount == 0) + { + __instance.roleChance = 0; + } + __instance.OnValueChanged.Invoke(__instance); return false; } @@ -106,6 +121,11 @@ public static class OptionsPatches __instance.roleMaxCount = __instance.role.MaxCount; } + if (__instance.roleMaxCount == 0) + { + __instance.roleChance = 0; + } + __instance.OnValueChanged.Invoke(__instance); return false; } diff --git a/MiraAPI/Patches/Options/SettingPatches.cs b/MiraAPI/Patches/Options/SettingPatches.cs index 8fd6581..59b956c 100644 --- a/MiraAPI/Patches/Options/SettingPatches.cs +++ b/MiraAPI/Patches/Options/SettingPatches.cs @@ -1,5 +1,4 @@ -using System.Diagnostics.CodeAnalysis; -using System.Globalization; +using System.Globalization; using System.Linq; using HarmonyLib; using MiraAPI.GameOptions; @@ -24,7 +23,6 @@ public static class SettingPatches /// to skip original method. [HarmonyPrefix] [HarmonyPatch(typeof(FloatGameSetting), nameof(FloatGameSetting.GetValueString))] - [SuppressMessage("Style", "IDE0045:Convert to conditional expression", Justification = "Warning cascades into forcing the entire tree to be ternary operators.")] public static bool ValueStringPatch( FloatGameSetting __instance, ref string __result, diff --git a/MiraAPI/Patches/RoleGuidePatches.cs b/MiraAPI/Patches/RoleGuidePatches.cs index 427dcf9..62eedc9 100644 --- a/MiraAPI/Patches/RoleGuidePatches.cs +++ b/MiraAPI/Patches/RoleGuidePatches.cs @@ -37,11 +37,10 @@ public static class RoleGuidePatches private static readonly List RoleEntries = []; private static readonly List ModifierEntries = []; - public static GameObject SearchComponentContainer; + private static GameObject searchComponentContainer; public static PassiveButton SearchIconButton; private static SpriteRenderer _searchIconIdle; private static SpriteRenderer _searchIconHover; - public static TextMeshPro OrderSortingTmp; public static PassiveButton SearchSortingOrderButton; private static SpriteRenderer _searchSortingOrderIdle; private static SpriteRenderer _searchSortingOrderHover; @@ -286,6 +285,7 @@ public static class RoleGuidePatches _titleText.transform.GetComponent().Destroy(); } } + if (!_titleIcon) { var titleIconObj = new GameObject("TitleIcon"); @@ -397,14 +397,14 @@ public static class RoleGuidePatches _guide = instance; _loading = false; - SearchComponentContainer = new GameObject(); - SearchComponentContainer.transform.SetParent(instance.MatchInfoParent.transform); - SearchComponentContainer.transform.localPosition = Vector3.zero; - instance.MatchInfoParent.transform.GetChild(1).transform.SetParent(SearchComponentContainer.transform); + searchComponentContainer = new GameObject(); + searchComponentContainer.transform.SetParent(instance.MatchInfoParent.transform); + searchComponentContainer.transform.localPosition = Vector3.zero; + instance.MatchInfoParent.transform.GetChild(1).transform.SetParent(searchComponentContainer.transform); var sortingOrderButton = Object.Instantiate( HudManager.Instance.SettingsButton, - SearchComponentContainer.transform); + searchComponentContainer.transform); sortingOrderButton.gameObject.SetActive(true); SearchSortingOrderButton = sortingOrderButton.GetComponent(); SetupSearchButton( @@ -419,7 +419,7 @@ public static class RoleGuidePatches var sortingGroupButton = Object.Instantiate( sortingOrderButton, - SearchComponentContainer.transform); + searchComponentContainer.transform); sortingGroupButton.gameObject.SetActive(true); SearchSortingGroupButton = sortingGroupButton.GetComponent(); SetupSearchButton( @@ -434,7 +434,7 @@ public static class RoleGuidePatches var sortingFilterButton = Object.Instantiate( sortingOrderButton, - SearchComponentContainer.transform); + searchComponentContainer.transform); sortingFilterButton.gameObject.SetActive(true); SearchSortingFilterButton = sortingFilterButton.GetComponent(); SetupSearchButton( @@ -512,7 +512,7 @@ public static class RoleGuidePatches var searchBox = Object.Instantiate( instance.TabButtons[2].gameObject, - SearchComponentContainer.transform); + searchComponentContainer.transform); var searchButton = searchBox.GetComponent(); var tmpText = searchButton.transform.GetChild(0).GetComponent(); tmpText.GetComponent().Destroy(); @@ -657,23 +657,23 @@ public static class RoleGuidePatches modifiersButton.OnClick.AddListener((Action)(() => OpenModifiersTab())); instance.TabButtons.Add(modifiersButton); - OrderSortingTmp = Object.Instantiate( + var orderSortingTmp = Object.Instantiate( _titleText, sortingOrderButton.transform); - OrderSortingTmp.text = MiraLocaleManager.Get("MiraApi.Wiki.OrderLabel"); - OrderSortingTmp.fontSize = OrderSortingTmp.fontSizeMax = 3f; - OrderSortingTmp.alignment = TextAlignmentOptions.Center; - OrderSortingTmp.horizontalAlignment = HorizontalAlignmentOptions.Center; - OrderSortingTmp.transform.localPosition = new Vector3(-0.65f, 0.4f, 0); + orderSortingTmp.text = MiraLocaleManager.Get("MiraApi.Wiki.OrderLabel"); + orderSortingTmp.fontSize = orderSortingTmp.fontSizeMax = 3f; + orderSortingTmp.alignment = TextAlignmentOptions.Center; + orderSortingTmp.horizontalAlignment = HorizontalAlignmentOptions.Center; + orderSortingTmp.transform.localPosition = new Vector3(-0.65f, 0.4f, 0); GroupSortingTmp = Object.Instantiate( - OrderSortingTmp, + orderSortingTmp, sortingGroupButton.transform); - OrderSortingTmp.text = MiraLocaleManager.Get("MiraApi.Wiki.GroupingLabel"); + GroupSortingTmp.text = MiraLocaleManager.Get("MiraApi.Wiki.GroupingLabel"); GroupSortingTmp.transform.localPosition = new Vector3(-0.65f, 0.4f, 0); FilterSortingTmp = Object.Instantiate( - OrderSortingTmp, + orderSortingTmp, sortingFilterButton.transform); FilterSortingTmp.text = MiraLocaleManager.Get("MiraApi.Wiki.FilterLabel"); FilterSortingTmp.transform.localPosition = new Vector3(-0.65f, 0.4f, 0); @@ -767,9 +767,15 @@ public static class RoleGuidePatches } } - public static void OpenModifiersTab() => OpenTab(ModifiersTabIndex); + public static void OpenModifiersTab() + { + OpenTab(ModifiersTabIndex); + } - public static void OpenRolesTab() => OpenTab(RolesTabIndex); + public static void OpenRolesTab() + { + OpenTab(RolesTabIndex); + } private static void SetNoResultsText(GameObject message) { @@ -791,7 +797,7 @@ public static class RoleGuidePatches } } - public sealed class DetailedPanel(string title, string category, string modId, RoleBehaviour? role, GameModifier? modifier) + private sealed class DetailedPanel(string title, string category, string modId, RoleBehaviour? role, GameModifier? modifier) { public MatchInfoRolePanel? Panel { get; set; } public string Title { get; } = title; @@ -861,14 +867,7 @@ public static class RoleGuidePatches private static IEnumerator CoPopulate(float delay) { - if (delay > 0f) - { - yield return new WaitForSeconds(delay); - } - else - { - yield return null; - } + yield return delay > 0f ? new WaitForSeconds(delay) : null; if (!_guide) { @@ -1208,14 +1207,8 @@ public static class RoleGuidePatches } var stepUp = (SortingFilter)((int)_sortFilter + 1); - if (Enum.IsDefined(stepUp)) - { - _sortFilter = stepUp; - } - else - { - _sortFilter = SortingFilter.EnabledOnly; - } + + _sortFilter = Enum.IsDefined(stepUp) ? stepUp : SortingFilter.EnabledOnly; MiraApiPlugin.WikiSortingFilter.Value = _sortFilter; @@ -1259,14 +1252,8 @@ public static class RoleGuidePatches } var stepUp = (SortingMethod)((int)_sortMethod + 1); - if (Enum.IsDefined(stepUp)) - { - _sortMethod = stepUp; - } - else - { - _sortMethod = SortingMethod.Alphabetical; - } + + _sortMethod = Enum.IsDefined(stepUp) ? stepUp : SortingMethod.Alphabetical; MiraApiPlugin.WikiSortingMethod.Value = _sortMethod; @@ -1459,7 +1446,7 @@ public static class RoleGuidePatches } _wikiScroller?.gameObject.SetActive(false); - SearchComponentContainer?.SetActive(true); + searchComponentContainer?.SetActive(true); if (tabIndex == SettingsTabIndex) { EnterSettingsTab(); @@ -1522,9 +1509,9 @@ public static class RoleGuidePatches _currentWikiPage.Destroy(); } - if (SearchComponentContainer) + if (searchComponentContainer) { - SearchComponentContainer.SetActive(false); + searchComponentContainer.SetActive(false); } if (_wikiScroller == null) @@ -2004,20 +1991,20 @@ public static class RoleGuidePatches } } -public enum SortingGroups +internal enum SortingGroups { Ungrouped, Faction, AmountChance, } -public enum SortingMethod +internal enum SortingMethod { Alphabetical, AlphabeticalDescending, } -public enum SortingFilter +internal enum SortingFilter { EnabledOnly, DisabledOnly, diff --git a/MiraAPI/Patches/Stubs/RoleBehaviourStubs.cs b/MiraAPI/Patches/Stubs/RoleBehaviourStubs.cs index f047fd3..b856d22 100644 --- a/MiraAPI/Patches/Stubs/RoleBehaviourStubs.cs +++ b/MiraAPI/Patches/Stubs/RoleBehaviourStubs.cs @@ -39,10 +39,10 @@ public static class RoleBehaviourStubs } /// - /// Stub method for . + /// Stub method for . /// /// The object. - /// The to append the task hint to. + /// The to append the task hint to. [HarmonyReversePatch] [HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.AppendTaskHint), typeof(Il2CppSystem.Text.StringBuilder))] [MethodImpl(MethodImplOptions.NoInlining)] diff --git a/MiraAPI/Presets/SavePresetPopup.cs b/MiraAPI/Presets/SavePresetPopup.cs index b9932ff..9405e83 100644 --- a/MiraAPI/Presets/SavePresetPopup.cs +++ b/MiraAPI/Presets/SavePresetPopup.cs @@ -16,6 +16,7 @@ namespace MiraAPI.Presets; [RegisterInIl2Cpp] [SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Unity convention.")] +[SuppressMessage("Design", "CA1050:Declare types in namespaces", Justification = "Unity script.")] #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member (Justification: Unity fields; ignore.) public class SavePresetPopup(nint cppPtr) : Minigame(cppPtr) { diff --git a/MiraAPI/Roles/ICustomRole.cs b/MiraAPI/Roles/ICustomRole.cs index 4d5e247..88b1f85 100644 --- a/MiraAPI/Roles/ICustomRole.cs +++ b/MiraAPI/Roles/ICustomRole.cs @@ -345,7 +345,14 @@ public interface ICustomRole : IOptionable /// Gets the list of abilities or other similar information to display below the text of a role's wiki page. /// [HideFromIl2Cpp] - public List WikiAbilities => []; + List WikiAbilities => []; } +/// +/// A data holder of an ability's wiki entry. +/// +/// The name of the ability. +/// The type of the ability. +/// The description of the ability. +/// The icon sprite of the ability. public record struct AdvancedWikiAbilityDescription(string Name, string AbilityType, string Description, LoadableAsset Icon); diff --git a/MiraAPI/Translation/MiraLocaleManager.cs b/MiraAPI/Translation/MiraLocaleManager.cs index d26f422..0bce8ca 100644 --- a/MiraAPI/Translation/MiraLocaleManager.cs +++ b/MiraAPI/Translation/MiraLocaleManager.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; @@ -162,7 +161,6 @@ public static class MiraLocaleManager /// The string id to find. /// Fallback string to use if no translation is found. /// A based on the key provided. - [SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Warning cascades into forcing the entire tree to be ternary operators.")] public static string Get(MiraLanguage language, string key, string fallback = "") { if (Locale.TryGetValue(language, out var translations) && diff --git a/MiraAPI/Utilities/Assets/AddressablesLoader.cs b/MiraAPI/Utilities/Assets/AddressablesLoader.cs index 39626e9..fee0a72 100644 --- a/MiraAPI/Utilities/Assets/AddressablesLoader.cs +++ b/MiraAPI/Utilities/Assets/AddressablesLoader.cs @@ -1,48 +1,39 @@ -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using Il2CppInterop.Runtime.Attributes; -using MiraAPI.Patches.Menu; -using Reactor.Utilities; -using UnityEngine.AddressableAssets; -using UnityEngine.ResourceManagement.AsyncOperations; +using System; +using System.Diagnostics.CodeAnalysis; namespace MiraAPI.Utilities.Assets; /// /// The component for loading Addressables, and cosmetics. /// +[Obsolete("This system has been deprecated in favour of CorsacCosmetics. This will be removed in a future version.", true)] +[SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Part of obsolete code.")] public static class AddressablesLoader { - private static readonly List<(string Location, string ProviderSuffix)> CatalogLocations = []; - private static readonly List LoadedLocations = []; - - private static readonly List RegisteredHatKeys = []; - private static readonly List<(string, string)> RegisteredVisorKeys = []; - private static readonly List<(string, string)> RegisteredNameplateKeys = []; - private static readonly List RegisteredSkinKeys = []; - - private static bool _isInitialized; - /// /// Gets a value indicating whether hats have been loaded by the addressables system. /// - public static bool AddressableHatsExist { get; private set; } + public static bool AddressableHatsExist => false; /// /// Gets a value indicating whether visors have been loaded by the addressables system. /// - public static bool AddressableVisorsExist { get; private set; } + public static bool AddressableVisorsExist => false; /// /// Gets a value indicating whether nameplates have been loaded by the addressables system. /// - public static bool AddressableNameplatesExist { get; private set; } + public static bool AddressableNameplatesExist => false; /// /// Gets a value indicating whether skins have been loaded by the addressables system. /// - public static bool AddressableSkinsExist { get; private set; } + public static bool AddressableSkinsExist => false; + + /// + /// Gets a value indicating whether catalogs have been loaded by the addressables system. + /// + public static bool CatalogsExist => false; /// /// Registers a specific addressables package to load asynchronously at the start of the game, when possible. @@ -51,13 +42,7 @@ public static class AddressablesLoader /// The suffix of the provider for an addressables package. public static void RegisterCatalog(string location, string providerSuffix = "") { - if (_isInitialized) - { - Error("AddressablesLoader has already been initialized, cannot register more catalogs."); - return; - } - - CatalogLocations.Add((location, providerSuffix)); + Warning("The addressables system has been deprecated. None of the registered assets will be added."); } /// @@ -66,14 +51,7 @@ public static class AddressablesLoader /// The key/label/group for a List . public static void RegisterHats(string addressablesKey) { - if (_isInitialized) - { - Error("AddressablesLoader has already been initialized, cannot register more keys for hats."); - return; - } - - AddressableHatsExist = true; - RegisteredHatKeys.Add(addressablesKey); + Warning("The addressables system has been deprecated. None of the registered assets will be added."); } /// @@ -82,14 +60,7 @@ public static class AddressablesLoader /// The key/label/group for a List . public static void RegisterSkins(string addressablesKey) { - if (_isInitialized) - { - Error("AddressablesLoader has already been initialized, cannot register more keys for skins."); - return; - } - - AddressableSkinsExist = true; - RegisteredSkinKeys.Add(addressablesKey); + Warning("The addressables system has been deprecated. None of the registered assets will be added."); } /// @@ -99,14 +70,7 @@ public static class AddressablesLoader /// /// The title of the group for visors. public static void RegisterNameplates(string addressablesKey, string groupTitle) { - if (_isInitialized) - { - Error("AddressablesLoader has already been initialized, cannot register more keys for nameplates."); - return; - } - - AddressableNameplatesExist = true; - RegisteredNameplateKeys.Add((addressablesKey, groupTitle)); + Warning("The addressables system has been deprecated. None of the registered assets will be added."); } /// @@ -116,140 +80,6 @@ public static class AddressablesLoader /// The title of the group for visors. public static void RegisterVisors(string addressablesKey, string groupTitle) { - if (_isInitialized) - { - Error("AddressablesLoader has already been initialized, cannot register more keys for visors."); - return; - } - - AddressableVisorsExist = true; - RegisteredVisorKeys.Add((addressablesKey, groupTitle)); - } - - internal static void LoadAll() - { - if (_isInitialized) - { - Error("AddressablesLoader has already been initialized."); - return; - } - - _isInitialized = true; - foreach (var (location, providerSuffix) in CatalogLocations) - { - Coroutines.Start(CoLoadAddressables(location, providerSuffix)); - } - - Coroutines.Start(LoadCosmetics()); - } - - internal static IEnumerator CoLoadAddressables(string location, string suffix = "") - { - while (!AmongUsClient.Instance) yield return null; - - // Load the local/remote content catalog - var catalogOperation = Addressables.LoadContentCatalog(location, suffix); - yield return catalogOperation; - - // Check for errors - if (catalogOperation.Status != AsyncOperationStatus.Succeeded) - { - Error($"Failed to load catalog {location}."); - } - - Info($"Loaded addressables {location}."); - LoadedLocations.Add(location); - } - - [HideFromIl2Cpp] - internal static IEnumerator LoadCosmetics() - { - while (!AmongUsClient.Instance || CatalogLocations.Select(x => x.Location).Any(x => !LoadedLocations.Contains(x))) yield return null; - - var hatBehaviours = DiscoverData(RegisteredHatKeys); - hatBehaviours = [.. hatBehaviours.OrderBy(x => x.StoreName)]; - var skinBehaviours = DiscoverData(RegisteredSkinKeys); - skinBehaviours = [.. skinBehaviours.OrderBy(x => x.StoreName)]; - var namePlateBehaviours = DiscoverAndReportData(RegisteredNameplateKeys); - namePlateBehaviours = [.. namePlateBehaviours.OrderBy(x => x.Category)]; - var visorBehaviours = DiscoverAndReportData(RegisteredVisorKeys); - visorBehaviours = [.. visorBehaviours.OrderBy(x => x.Category)]; - - var hatData = new List(); - hatData.AddRange(HatManager.Instance.allHats); - hatData.ForEach(x => x.StoreName = "Vanilla"); - HatManager.Instance.allHats = PrepareArray(hatData, hatBehaviours); - - var skinData = new List(); - skinData.AddRange(HatManager.Instance.allSkins); - skinData.ForEach(x => x.StoreName = "Vanilla"); - HatManager.Instance.allSkins = PrepareArray(skinData, skinBehaviours); - - var visorData = new List(); - visorData.AddRange(HatManager.Instance.allVisors); - VisorsTabPatches.AddRange(visorBehaviours); - HatManager.Instance.allVisors = PrepareArray(visorData, [.. visorBehaviours.Select(x => x.Data)]); - - var namePlateData = new List(); - namePlateData.AddRange(HatManager.Instance.allNamePlates); - NameplatesTabPatches.AddRange(namePlateBehaviours); - HatManager.Instance.allNamePlates = PrepareArray(namePlateData, [.. namePlateBehaviours.Select(x => x.Data)]); - } - - private static T[] PrepareArray(List data, List behaviours) - where T : CosmeticData - { - var count = data.Count; - for (var i = 0; i < behaviours.Count; i++) - { - behaviours[i].displayOrder = count + i; - data.Add(behaviours[i]); - } - - return [.. data]; - } - - private static List DiscoverData(List tags) - { - var behaviours = new List(); - - foreach (var tag in tags) - { - try - { - var allLocations = Addressables.LoadResourceLocationsAsync(tag).WaitForCompletion(); - var assets = Addressables.LoadAssetsAsync(allLocations, null, false).WaitForCompletion(); - var array = new CppCollections.List(assets.Pointer); - behaviours.AddRange(array.ToArray()); - } - catch - { - Error($"Failed to find tag {tag}"); - } - } - - return behaviours; - } - - private static List<(string Category, T Data)> DiscoverAndReportData(List<(string Tag, string Category)> tags) - { - var behaviours = new List<(string, T)>(); - - foreach (var tag in tags) - { - try - { - var allLocations = Addressables.LoadResourceLocationsAsync(tag.Tag).WaitForCompletion(); - var assets = Addressables.LoadAssetsAsync(allLocations, null, false).WaitForCompletion(); - var array = new CppCollections.List(assets.Pointer); - behaviours.AddRange(array.ToArray().Select(x => (tag.Category, x))); - } - catch - { - Error($"Failed to find tag {tag}"); - } - } - - return behaviours; + Warning("The addressables system has been deprecated. None of the registered assets will be added."); } } diff --git a/MiraAPI/Utilities/Assets/AudioTools.cs b/MiraAPI/Utilities/Assets/AudioTools.cs new file mode 100644 index 0000000..075b65c --- /dev/null +++ b/MiraAPI/Utilities/Assets/AudioTools.cs @@ -0,0 +1,159 @@ +using System; +using System.IO; +using System.Reflection; +using System.Resources; +using System.Runtime.InteropServices; +using System.Text; +using UnityEngine; + +namespace MiraAPI.Utilities.Assets; + +/// +/// A utility class for various audio-related operations. +/// +public static class AudioTools +{ + /// + /// Loads and returns an audio clip from a resource path using the specified . + /// + /// The path to the resource within the . + /// The from which to load the resource. + /// A object loaded from the specified resource path. + /// Attempted to load an Audio file in non WAV format. + /// Stream failed to load. Check if the name of your asset was correct. + public static AudioClip LoadAudioFromResources(string resourcePath, Assembly assembly) + { + using var assetStream = assembly.GetManifestResourceStream(resourcePath) + ?? throw new MissingManifestResourceException($"Stream failed to load. Check if the asset name is correct: {resourcePath}"); + + using var reader = new BinaryReader(assetStream); + + // Read RIFF header + if (Encoding.ASCII.GetString(reader.ReadBytes(4)) != "RIFF") + { + throw new NotSupportedException("Invalid WAV file (missing RIFF header)."); + } + + reader.ReadInt32(); // File size (ignore) + + if (Encoding.ASCII.GetString(reader.ReadBytes(4)) != "WAVE") + { + throw new NotSupportedException("Invalid WAV file (missing WAVE header)."); + } + + // Read chunks + int channels = 0, sampleRate = 0, bitsPerSample = 0; + byte[]? audioData = null; + + while (reader.BaseStream.Position < reader.BaseStream.Length) + { + var chunkId = Encoding.ASCII.GetString(reader.ReadBytes(4)); + var chunkSize = reader.ReadInt32(); + + // Format chunk + if (chunkId == "fmt ") + { + int audioFormat = reader.ReadInt16(); + channels = reader.ReadInt16(); + sampleRate = reader.ReadInt32(); + reader.ReadInt32(); // Byte rate (ignore) + reader.ReadInt16(); // Block align (ignore) + bitsPerSample = reader.ReadInt16(); + + if (audioFormat != 1) // Only PCM supported + throw new NotSupportedException("Only PCM WAV files are supported."); + } + + // Data chunk + else if (chunkId == "data") + { + audioData = reader.ReadBytes(chunkSize); + break; // No need to read further + } + else + { + reader.BaseStream.Seek(chunkSize, SeekOrigin.Current); // Skip unknown chunks + } + } + + if (audioData == null) + { + throw new InvalidOperationException("WAV file does not contain audio data."); + } + + if (channels == 0 || sampleRate == 0 || bitsPerSample == 0) + { + throw new InvalidOperationException("WAV file does not contain valid format information."); + } + + // Convert PCM data to float array + var samples = ConvertPcmToFloat(audioData, bitsPerSample); + + // Create the AudioClip + var audioClip = AudioClip.Create(resourcePath, samples.Length / channels, channels, sampleRate, false); + audioClip.SetData(samples, 0); + + return audioClip; + } + + // This is somewhat magic to me, I just copied it from elsewhere. + // Could have been written better, so here - Az + private static float[] ConvertPcmToFloat(byte[] pcmData, int bitsPerSample) + { + var sampleCount = pcmData.Length / (bitsPerSample / 8); + var floatData = new float[sampleCount]; + + ReadOnlySpan source = pcmData; + Span destination = floatData; + + switch (bitsPerSample) + { + case 8: + for (var i = 0; i < sampleCount; i++) + { + destination[i] = (source[i] - 128) / 128f; // 8-bit PCM is unsigned + } + + break; + + case 16: + var shortSource = MemoryMarshal.Cast(source); + + for (var i = 0; i < sampleCount; i++) + { + destination[i] = shortSource[i] / 32768f; + } + + break; + + case 24: + for (int i = 0, byteIndex = 0; i < sampleCount; i++, byteIndex += 3) + { + var sample24 = source[byteIndex] | (source[byteIndex + 1] << 8) | (source[byteIndex + 2] << 16); + + // Convert from unsigned to signed + if (sample24 > 0x7FFFFF) + sample24 -= 0x1000000; + + destination[i] = sample24 / 8388608f; + } + + break; + + case 32: + var intSource = MemoryMarshal.Cast(source); + + for (var i = 0; i < sampleCount; i++) + { + destination[i] = intSource[i] / 2147483648f; + } + + break; + + default: + throw new NotSupportedException($"Unsupported bit depth: {bitsPerSample}"); + } + + return floatData; + } +} diff --git a/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs b/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs index 1bb75ae..49529a5 100644 --- a/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs +++ b/MiraAPI/Utilities/Assets/LoadableAudioResourceAsset.cs @@ -1,8 +1,4 @@ -using System; -using System.IO; using System.Reflection; -using System.Resources; -using System.Text; using UnityEngine; namespace MiraAPI.Utilities.Assets; @@ -15,118 +11,14 @@ public class LoadableAudioResourceAsset(string path) : LoadableAsset { private readonly Assembly _assembly = Assembly.GetCallingAssembly(); - /// - /// Loads the asset from embedded resources. - /// - /// The asset to load. - /// Attempted to load an Audio file in non WAV format. - /// Stream failed to load. Check if the name of your asset was correct. + /// public override AudioClip LoadAsset() { - using var assetStream = _assembly.GetManifestResourceStream(path) - ?? throw new MissingManifestResourceException($"Stream failed to load. Check if the asset name is correct: {path}"); - - using var reader = new BinaryReader(assetStream); - - // Read RIFF header - if (Encoding.ASCII.GetString(reader.ReadBytes(4)) != "RIFF") + if (!LoadedAsset) { - throw new NotSupportedException("Invalid WAV file (missing RIFF header)."); + LoadedAsset = AudioTools.LoadAudioFromResources(path, _assembly); } - reader.ReadInt32(); // File size (ignore) - - if (Encoding.ASCII.GetString(reader.ReadBytes(4)) != "WAVE") - { - throw new NotSupportedException("Invalid WAV file (missing WAVE header)."); - } - - // Read chunks - int channels = 0, sampleRate = 0, bitsPerSample = 0; - byte[]? audioData = null; - - while (reader.BaseStream.Position < reader.BaseStream.Length) - { - var chunkId = Encoding.ASCII.GetString(reader.ReadBytes(4)); - var chunkSize = reader.ReadInt32(); - - // Format chunk - if (chunkId == "fmt ") - { - int audioFormat = reader.ReadInt16(); - channels = reader.ReadInt16(); - sampleRate = reader.ReadInt32(); - reader.ReadInt32(); // Byte rate (ignore) - reader.ReadInt16(); // Block align (ignore) - bitsPerSample = reader.ReadInt16(); - - if (audioFormat != 1) // Only PCM supported - throw new NotSupportedException("Only PCM WAV files are supported."); - } - - // Data chunk - else if (chunkId == "data") - { - audioData = reader.ReadBytes(chunkSize); - break; // No need to read further - } - else - { - reader.BaseStream.Seek(chunkSize, SeekOrigin.Current); // Skip unknown chunks - } - } - - if (audioData == null) - { - throw new InvalidOperationException("WAV file does not contain audio data."); - } - - if (channels == 0 || sampleRate == 0 || bitsPerSample == 0) - { - throw new InvalidOperationException("WAV file does not contain valid format information."); - } - - // Convert PCM data to float array - var samples = ConvertPcmToFloat(audioData, bitsPerSample); - - // Create the AudioClip - var audioClip = AudioClip.Create(path, samples.Length / channels, channels, sampleRate, false); - audioClip.SetData(samples, 0); - - return audioClip; - } - - // This is somewhat magic to me, I just copied it from elsewhere. - private static float[] ConvertPcmToFloat(byte[] pcmData, int bitsPerSample) - { - var sampleCount = pcmData.Length / (bitsPerSample / 8); - var floatData = new float[sampleCount]; - - for (var i = 0; i < sampleCount; i++) - { - var byteIndex = i * (bitsPerSample / 8); - - switch (bitsPerSample) - { - case 8: - floatData[i] = (pcmData[byteIndex] - 128) / 128f; // 8-bit PCM is unsigned - break; - case 16: - floatData[i] = BitConverter.ToInt16(pcmData, byteIndex) / 32768f; - break; - case 24: - var sample24 = pcmData[byteIndex] | (pcmData[byteIndex + 1] << 8) | (pcmData[byteIndex + 2] << 16); - if (sample24 > 0x7FFFFF) sample24 -= 0x1000000; // Convert from unsigned to signed - floatData[i] = sample24 / 8388608f; - break; - case 32: - floatData[i] = BitConverter.ToInt32(pcmData, byteIndex) / 2147483648f; - break; - default: - throw new NotSupportedException($"Unsupported bit depth: {bitsPerSample}"); - } - } - - return floatData; + return LoadedAsset!; } } diff --git a/MiraAPI/Utilities/Assets/LoadableBundleSubAssetHolder.cs b/MiraAPI/Utilities/Assets/LoadableBundleSubAssetHolder.cs index bc2e5c4..1507c42 100644 --- a/MiraAPI/Utilities/Assets/LoadableBundleSubAssetHolder.cs +++ b/MiraAPI/Utilities/Assets/LoadableBundleSubAssetHolder.cs @@ -1,7 +1,5 @@ using System; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using HarmonyLib; +using System.Collections.Generic; using Il2CppInterop.Runtime; using Reactor.Utilities.Extensions; using UnityEngine; @@ -11,71 +9,55 @@ namespace MiraAPI.Utilities.Assets; /// /// A utility class for loading multiple assets from an . /// -public class LoadableBundleSubAssetHolder +/// The name of the assets to pull from. +/// The that contains the assets. +public class LoadableBundleSubAssetHolder(string[] names, AssetBundle bundle) { - private readonly string[] spriteNames; - private readonly AssetBundle bundle; - /// /// Gets the sprites contained within the asset. /// public Sprite[] SubSprites { get; private set; } = []; - /// - /// Initializes a new instance of the class. - /// - /// The name of the assets to pull from. - /// The that contains the assets. - public LoadableBundleSubAssetHolder(string[] names, AssetBundle bundle) - { - this.bundle = bundle; - spriteNames = names; - } - /// /// Initializes a new instance of the class. /// /// The name of the asset. /// The that contains the assets. public LoadableBundleSubAssetHolder(string name, AssetBundle bundle) + : this([name], bundle) { - this.bundle = bundle; - spriteNames = [name]; } /// /// Attempts to load all of the sprite assets within the sprite sheet. /// /// Thrown if the asset is not actually a sprite sheet. - [SuppressMessage("Style", "IDE0270:Use coalesce expression", Justification = "Null coalescing bypasses Unity lifetime checks.")] public void TryInit() { - if (SubSprites.Length == 0) + if (SubSprites.Length != 0) + return; + + var newSprites = new List(); + var type = Il2CppType.From(typeof(Sprite)); + + foreach (var name in names) { - var newSprites = Array.Empty(); + var loadedAssets = bundle.LoadAssetWithSubAssets(name, type) + ?? throw new InvalidOperationException($"INVALID ASSETS: {name}"); - foreach (var name in spriteNames) + foreach (var obj in loadedAssets) { - var loadedAssets = bundle.LoadAssetWithSubAssets(name, Il2CppType.From(typeof(Sprite))).ToArray(); + var img = obj.TryCast(); - if (loadedAssets == null) - { - throw new InvalidOperationException($"INVALID ASSETS: {name}"); - } + if (img == null) + continue; - foreach (var obj in loadedAssets) - { - var img = obj.TryCast(); - if (img != null) - { - img.DontDestroy().DontUnload(); - newSprites = newSprites.AddToArray(img); - } - } + img.DontDestroy().DontUnload(); + newSprites.Add(img); } - - SubSprites = newSprites; } + + SubSprites = [.. newSprites]; } /// diff --git a/MiraAPI/Utilities/ControllableComparer.cs b/MiraAPI/Utilities/ControllableComparer.cs index 49c4b0e..5e7ac70 100644 --- a/MiraAPI/Utilities/ControllableComparer.cs +++ b/MiraAPI/Utilities/ControllableComparer.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; namespace MiraAPI.Utilities; @@ -9,7 +8,6 @@ internal sealed class ControllableComparer(T[] forcedToBottom, T[] forcedToTo where T : IComparable { /// - [SuppressMessage("Style", "IDE0046:Convert to conditional expression", Justification = "Warning cascades into forcing the entire tree to be ternary operators.")] public int Compare(T? x, T? y) { if ((forcedToBottom.Contains(x) && forcedToBottom.Contains(y)) || (forcedToTop.Contains(x) && forcedToTop.Contains(y))) diff --git a/MiraAPI/Utilities/Helpers.cs b/MiraAPI/Utilities/Helpers.cs index 3685089..618dca3 100644 --- a/MiraAPI/Utilities/Helpers.cs +++ b/MiraAPI/Utilities/Helpers.cs @@ -35,6 +35,11 @@ public static class Helpers private static readonly Regex TrailingZeroRegex = new(@"\.0+(?!\d)", RegexOptions.Compiled, TimeSpan.FromMilliseconds(100)); private static NumberOption? _advancedSettingsRowPrefab; + /// + /// Gets all of the options stored within the provided type. + /// + /// The type to get the options of. + /// A readonly list of options from the provided type. public static ReadOnlyCollection? GetModdedOptionsForType(Type classType) { var group = ModdedOptionsManager.Groups.FirstOrDefault(x => x.OptionableType == classType); @@ -42,6 +47,11 @@ public static class Helpers return group?.Children; } + /// + /// Gets the option text of the provided type. + /// + /// The type to get the text for. + /// The options text of the provided type. public static string GetOptionsText(Type classType) { var group = ModdedOptionsManager.Groups.FirstOrDefault(x => x.OptionableType == classType); @@ -840,7 +850,7 @@ public static class Helpers obj.transform.localScale = Vector3.one / MatchInfoGuideBaseScale; obj.transform.localPosition = new Vector3(0f, 0.5f, 0f); var scrollHeight = variableTextSizing - ? (desc.textBounds.size.y - 2.5f) + maxTextSize + 0.475f + ? desc.textBounds.size.y - 2.5f + maxTextSize + 0.475f : desc.textBounds.size.y - 2.5f + Mathf.Ceil(num / 2f) * 1.45f; parent.SetYBoundsMax(Mathf.Clamp(scrollHeight, 0f, 999f)); return obj; @@ -1067,6 +1077,7 @@ public static class Helpers panel.roleDescription.fontSizeMin = 1.5f; panel.roleDescription.ForceMeshUpdate(); } + panel.roleIcon.sprite = ability.Icon.LoadAsset(); panel.roleIcon.SetSizeLimit(0.13f);