diff --git a/MiraAPI/GameOptions/ISummarizedOptions.cs b/MiraAPI/GameOptions/ISummarizedOptions.cs new file mode 100644 index 0000000..60b5ea6 --- /dev/null +++ b/MiraAPI/GameOptions/ISummarizedOptions.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace MiraAPI.GameOptions; + +/// +/// Allows an option group to compress noisy option blocks in the wiki "Options" section. +/// Implementers can hide specific option keys and replace them with one or more summary lines. +/// +public interface ISummarizedOptions +{ + /// + /// Option string keys (StringNames) to omit from the wiki options list (e.g., a large set of related options). + /// + IReadOnlySet WikiHiddenOptionKeys { get; } + + /// + /// Summary lines to insert when the first hidden option would have appeared. + /// Lines should already be formatted as "Title: Value". + /// + IEnumerable GetWikiOptionSummaryLines(); +} \ No newline at end of file diff --git a/MiraAPI/Utilities/Helpers.cs b/MiraAPI/Utilities/Helpers.cs index eded3d3..e2221e7 100644 --- a/MiraAPI/Utilities/Helpers.cs +++ b/MiraAPI/Utilities/Helpers.cs @@ -1,17 +1,24 @@ -using System.Collections; +using System; +using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; +using System.Text; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes.Arrays; +using MiraAPI.GameOptions; +using MiraAPI.GameOptions.OptionTypes; using MiraAPI.Roles; +using MiraAPI.Translation; using MiraAPI.Utilities.Assets; using Rewired; using TMPro; using UnityEngine; using MethodBase = System.Reflection.MethodBase; using Object = UnityEngine.Object; +using Random = UnityEngine.Random; namespace MiraAPI.Utilities; @@ -20,6 +27,152 @@ namespace MiraAPI.Utilities; /// public static class Helpers { + public static ReadOnlyCollection? GetModdedOptionsForType(Type classType) + { + var optionGroups = + AccessTools.Field(typeof(ModdedOptionsManager), "Groups").GetValue(null) as List; + + return optionGroups?.FirstOrDefault(x => x.OptionableType == classType)?.Children; + } + + public static string GetOptionsText(Type classType) + { + var options = GetModdedOptionsForType(classType); + if (options == null) + { + return string.Empty; + } + + ISummarizedOptions? summaryProvider = null; + IReadOnlySet? hiddenKeys = null; + try + { + var optionGroups = + AccessTools.Field(typeof(ModdedOptionsManager), "Groups").GetValue(null) as List; + summaryProvider = + optionGroups?.FirstOrDefault(x => x.OptionableType == classType) as ISummarizedOptions; + hiddenKeys = summaryProvider?.WikiHiddenOptionKeys; + } + catch + { + summaryProvider = null; + hiddenKeys = null; + } + + var builder = new StringBuilder(); + builder.AppendLine(MiraApiPlugin.Culture, + $"\n \n{MiraLocaleManager.Get("Options")}"); + + var insertedSummary = false; + foreach (var option in options) + { + if (!insertedSummary && summaryProvider != null && hiddenKeys != null) + { + StringNames? key = option switch + { + ModdedToggleOption t => t.StringName, + ModdedEnumOption e => e.StringName, + ModdedNumberOption n => n.StringName, + _ => null + }; + if (key.HasValue && hiddenKeys.Contains(key.Value)) + { + foreach (var line in summaryProvider.GetWikiOptionSummaryLines()) + { + if (!string.IsNullOrWhiteSpace(line)) + { + builder.AppendLine(line); + } + } + + insertedSummary = true; + } + } + + switch (option) + { + case ModdedToggleOption toggleOption: + if (!toggleOption.Visible()) + { + continue; + } + + if (hiddenKeys != null && hiddenKeys.Contains(toggleOption.StringName)) + { + continue; + } + + builder.AppendLine(TranslationController.Instance.GetString(toggleOption.StringName) + ": " + + toggleOption.Value); + break; + /*case ModdedMultiSelectOption enumOption: + if (!enumOption.Visible()) + { + continue; + } + + builder.AppendLine(enumOption.Title + ": " + enumOption.Values[enumOption.Value]); + break;*/ + case ModdedEnumOption enumOption: + if (!enumOption.Visible()) + { + continue; + } + + if (hiddenKeys != null && hiddenKeys.Contains(enumOption.StringName)) + { + continue; + } + + builder.AppendLine(TranslationController.Instance.GetString(enumOption.StringName) + ": " + + MiraLocaleManager.Get(enumOption.Values[enumOption.Value], + enumOption.Values[enumOption.Value])); + break; + case ModdedNumberOption numberOption: + if (!numberOption.Visible()) + { + continue; + } + + if (hiddenKeys != null && hiddenKeys.Contains(numberOption.StringName)) + { + continue; + } + + var optionStr = numberOption.Data.GetValueString(numberOption.Value); + if (optionStr.Contains(".000")) + { + optionStr = optionStr.Replace(".000", ""); + } + else if (optionStr.Contains(".00")) + { + optionStr = optionStr.Replace(".00", ""); + } + else if (optionStr.Contains(".0")) + { + optionStr = optionStr.Replace(".0", ""); + } + + var title = TranslationController.Instance.GetString(numberOption.StringName); + if (numberOption is { NegativeWordValue: not "#", Value: -1 }) + { + builder.AppendLine(title + $": {numberOption.NegativeWordValue}"); + } + else if (numberOption is { ZeroWordValue: not "#", Value: 0 }) + { + builder.AppendLine(title + $": {numberOption.ZeroWordValue}"); + } + else + { + builder.AppendLine(title + ": " + optionStr); + } + + break; + } + } + + return builder.ToString(); + } /// /// Get all living players. ///