From 02f9c208040488691ea1284e3d994dfd2fd88f95 Mon Sep 17 00:00:00 2001 From: Atony <75191600+AtonyGit@users.noreply.github.com> Date: Sat, 7 Mar 2026 15:23:26 -0600 Subject: [PATCH] Add wip string option --- Directory.Build.props | 4 +- MiraAPI/GameOptions/ModdedOptionsManager.cs | 1 + .../OptionTypes/ModdedStringOption.cs | 183 ++++++++++++++++++ 3 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 MiraAPI/GameOptions/OptionTypes/ModdedStringOption.cs diff --git a/Directory.Build.props b/Directory.Build.props index 4b87d91..8fad4d6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -8,8 +8,8 @@ true - 0.3.8 - dev + 0.3.9 + wip All Of Us, XtraCube, Angxl All Of Us diff --git a/MiraAPI/GameOptions/ModdedOptionsManager.cs b/MiraAPI/GameOptions/ModdedOptionsManager.cs index 3b85a73..8045e3f 100644 --- a/MiraAPI/GameOptions/ModdedOptionsManager.cs +++ b/MiraAPI/GameOptions/ModdedOptionsManager.cs @@ -24,6 +24,7 @@ public static class ModdedOptionsManager private static readonly Dictionary TypeToGroup = []; internal static readonly Dictionary CreatedPlayerOptions = []; + internal static readonly Dictionary CreatedStringOptions = []; internal static readonly Dictionary ModdedOptions = []; internal static readonly List Groups = []; diff --git a/MiraAPI/GameOptions/OptionTypes/ModdedStringOption.cs b/MiraAPI/GameOptions/OptionTypes/ModdedStringOption.cs new file mode 100644 index 0000000..70206db --- /dev/null +++ b/MiraAPI/GameOptions/OptionTypes/ModdedStringOption.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using HarmonyLib; +using Il2CppInterop.Runtime.InteropTypes.Arrays; +using MiraAPI.Networking; +using Reactor.Localization.Utilities; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace MiraAPI.GameOptions.OptionTypes; + +/// +/// An option for selecting an enum value. +/// +public class ModdedStringOption : ModdedOption +{ + /// + /// Gets or sets the string values of the option. + /// + public string[] Values { get; set; } + + /// + /// Gets or sets the String Name values of the option. + /// + public StringNames[] StringNameValues { get; set; } + + /// + /// Gets the string's index + /// + /// The option's string value. + /// The option's value in the index. + public int GetIndex(string value, int location) + { + if (Values.Contains(value)) + { + return Values.ToList().IndexOf(value); + } + Info($"Cannot find a valid index for {value} in {location}. Returning 0 instead. Values: {string.Join(", ", Values)}"); + return 0; + } + + /// + /// Adds a value to the option. + /// + /// The option's string value. + /// The additional value's index on the list. + public void RegisterExtraValue(string value, int index = -1) + { + if (!Values.Contains(value)) + { + if (index <= -1) + { + Values.AddItem(value); + StringNameValues.AddItem(CustomStringName.CreateAndRegister(value)); + } + else + { + var newVals = Values.ToList(); + newVals.Insert(index, value); + Values = newVals.ToArray(); + var newStrVals = StringNameValues.ToList(); + newStrVals.Insert(index, CustomStringName.CreateAndRegister(value)); + StringNameValues = newStrVals.ToArray(); + } + } + + if (Data != null) + { + var data = (StringGameSetting)Data; + data.Values = StringNameValues; + + data.Index = GetIndex(Value, 1); + if (OptionBehaviour != null) + { + var strOpt = OptionBehaviour.TryCast(); + if (strOpt != null) + { + strOpt.Values = StringNameValues; + strOpt.Value = GetIndex(Value, 2); + Warning("StringOption is valid"); + } + else + { + Error("StringOption is null."); + } + Warning("OptionBehaviour is valid"); + } + else + { + Error("OptionBehaviour is null."); + } + Warning("Data is valid"); + } + else + { + Error("Data is null."); + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The title of the option. + /// The default value as a string. + /// An option list of string values to use. + /// Whether to include this option in the preset or not. + public ModdedStringOption(string title, string defaultValue, string[] values, bool includeInPreset=true) : base(title, defaultValue, includeInPreset) + { + Values = values; + Data = ScriptableObject.CreateInstance(); + var data = (StringGameSetting)Data; + + data.Title = StringName; + data.Type = global::OptionTypes.String; + StringNameValues = values.Select(CustomStringName.CreateAndRegister).ToArray(); + data.Values = StringNameValues; + + data.Index = GetIndex(Value, 3); + } + + /// + public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, PlayerOption playerOpt, Transform container) + { + var stringOption = Object.Instantiate(stringOpt, container); + stringOption.name = + $"{ParentMod!.OptionsTitleText}.StringOption.{TranslationController.Instance.GetString(StringName)}"; + + stringOption.SetUpFromData(Data, 20); + stringOption.OnValueChanged = (Il2CppSystem.Action)ValueChanged; + + // SetUpFromData method doesnt work correctly so we must set the values manually + stringOption.Title = StringName; + stringOption.Values = (Data as StringGameSetting)?.Values ?? new Il2CppStructArray(0); + stringOption.Value = GetIndex(Value, 4); + + OptionBehaviour = stringOption; + ModdedOptionsManager.CreatedStringOptions.TryAdd(stringOption, this); + + return stringOption; + } + + /// + public override float GetFloatData() + { + return Convert.ToSingle(Value, NumberFormatInfo.InvariantInfo); + } + + /// + public override NetData GetNetData() + { + return new NetData(Id, Encoding.Unicode.GetBytes(Convert.ToString(Value, NumberFormatInfo.InvariantInfo)!)); + } + + /// + public override void HandleNetData(byte[] data) + { + SetValue(Encoding.Unicode.GetString(data)); + } + + /// + public override string GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour) + { + return Values[optionBehaviour.GetInt()]; + } + + /// + protected override void OnValueChanged(string newValue) + { + HudManager.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(GetIndex(newValue, 5)), false); + if (!OptionBehaviour) + { + return; + } + + if (OptionBehaviour is StringOption opt) + { + opt.Value = GetIndex(newValue, 5); + } + } +}