remove ModdedStringOption.cs, improve code in Options API

This commit is contained in:
XtraCube committed 2024-08-31 10:41:16 -04:00
1 parent dc5bb4177f
commit 0429cd8005
14 files changed
+177 -207

No files matched your search

+5 -8
View File
@@ -19,16 +19,13 @@ public class ExampleOptions : AbstractOptionGroup
[ModdedNumberOption("Number Opt", min: 0, max: 10, suffixType: MiraNumberSuffixes.Percent)]
public float NumberOpt { get; set; } = 4f;
[ModdedStringOption("String Opt", ["Hello", "Hey", "Bye"])]
public int StringOpt { get; set; } = 2;
[ModdedEnumOption("Best API", typeof(BestApiEnum), ["Mira API", "Mitochondria", "Reactor"])]
public BestApiEnum EnumOpt { get; set; } = BestApiEnum.MiraAPI;
[ModdedEnumOption("Best API", typeof(BestApi), ["Mira API", "Mitochondria", "Reactor"])]
public BestApi Opt { get; set; } = BestApi.MiraAPI;
}
public enum BestApiEnum
public enum BestApi
{
MiraAPI,
Mitochondria,
Reactor
}
Reactor,
}
@@ -15,8 +15,6 @@ public class ExampleOptions2 : AbstractOptionGroup
Visible = () => OptionGroupSingleton<ExampleOptions2>.Instance.ToggleOpt1.Value,
};
public ModdedStringOption StringOpt { get; } = new("String Opt", 0, ["Choice 1", "Choice 2", "Choice 3"]);
public ModdedEnumOption EnumOpt { get; } = new("Enum Opt", 0, typeof(TestingData))
{
ChangedEvent = x => Logger<ExamplePlugin>.Info($"changed Enum Opt to {x}"),
@@ -4,7 +4,11 @@ using System.Reflection;
namespace MiraAPI.GameOptions.Attributes;
public class ModdedEnumOptionAttribute(string title, Type enumType, string[] values = null, Type? roleType = null)
/// <summary>
/// Attribute for creating an enum option.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class ModdedEnumOptionAttribute(string title, Type enumType, string[]? values = null, Type? roleType = null)
: ModdedOptionAttribute(title, roleType)
{
internal override IModdedOption CreateOption(object? value, PropertyInfo property)
@@ -13,15 +17,20 @@ public class ModdedEnumOptionAttribute(string title, Type enumType, string[] val
return opt;
}
/// <inheritdoc />
public override void SetValue(object value)
{
var opt = HolderOption as ModdedEnumOption;
opt.SetValue((int)value);
opt?.SetValue((int)value);
}
/// <inheritdoc />
public override object GetValue()
{
var opt = HolderOption as ModdedEnumOption;
return Enum.ToObject(enumType, opt.Value);
if (HolderOption is ModdedEnumOption opt)
{
return Enum.ToObject(enumType, opt.Value);
}
throw new InvalidOperationException($"HolderOption for option \"{Title}\" with EnumType ${enumType.FullName} is not a ModdedEnumOption");
}
}
}
@@ -5,6 +5,10 @@ using System.Reflection;
namespace MiraAPI.GameOptions.Attributes;
/// <summary>
/// A number option attribute for the modded options system.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class ModdedNumberOptionAttribute(
string title,
float min,
@@ -12,24 +16,28 @@ public class ModdedNumberOptionAttribute(
float increment = 1,
MiraNumberSuffixes suffixType = MiraNumberSuffixes.None,
bool zeroInfinity = false,
Type roleType = null)
Type? roleType = null)
: ModdedOptionAttribute(title, roleType)
{
internal override IModdedOption CreateOption(object value, PropertyInfo property)
internal override IModdedOption CreateOption(object? value, PropertyInfo property)
{
var toggleOpt = new ModdedNumberOption(Title, (float)value, min, max, increment, suffixType, zeroInfinity, RoleType);
return toggleOpt;
return new ModdedNumberOption(Title, (float)(value ?? min+increment), min, max, increment, suffixType, zeroInfinity, RoleType);
}
/// <inheritdoc />
public override void SetValue(object value)
{
var toggleOpt = HolderOption as ModdedNumberOption;
toggleOpt.SetValue((float)value);
var opt = HolderOption as ModdedNumberOption;
opt?.SetValue((float)value);
}
/// <inheritdoc />
public override object GetValue()
{
var toggleOpt = HolderOption as ModdedNumberOption;
return toggleOpt.Value;
if (HolderOption is ModdedNumberOption opt)
{
return opt.Value;
}
throw new InvalidOperationException($"HolderOption for option \"{Title}\" is not a ModdedNumberOption");
}
}
}
@@ -1,27 +0,0 @@
using MiraAPI.GameOptions.OptionTypes;
using System;
using System.Reflection;
namespace MiraAPI.GameOptions.Attributes;
public class ModdedStringOptionAttribute(string title, string[] values, Type roleType = null)
: ModdedOptionAttribute(title, roleType)
{
internal override IModdedOption CreateOption(object value, PropertyInfo property)
{
var opt = new ModdedStringOption(Title, (int)value, values, RoleType);
return opt;
}
public override void SetValue(object value)
{
var opt = HolderOption as ModdedStringOption;
opt.SetValue((int)value);
}
public override object GetValue()
{
var opt = HolderOption as ModdedStringOption;
return opt.Value;
}
}
@@ -4,23 +4,34 @@ using System.Reflection;
namespace MiraAPI.GameOptions.Attributes;
public class ModdedToggleOptionAttribute(string title, Type roleType = null) : ModdedOptionAttribute(title, roleType)
/// <summary>
/// Attribute for a toggle option.
/// </summary>
/// <param name="title">The option title.</param>
/// <param name="roleType">An optional role type.</param>
[AttributeUsage(AttributeTargets.Property)]
public class ModdedToggleOptionAttribute(string title, Type? roleType = null) : ModdedOptionAttribute(title, roleType)
{
internal override IModdedOption CreateOption(object value, PropertyInfo property)
internal override IModdedOption CreateOption(object? value, PropertyInfo property)
{
var toggleOpt = new ModdedToggleOption(Title, (bool)value, RoleType);
var toggleOpt = new ModdedToggleOption(Title, (bool)(value ?? false), RoleType);
return toggleOpt;
}
/// <inheritdoc />
public override void SetValue(object value)
{
var toggleOpt = HolderOption as ModdedToggleOption;
toggleOpt.SetValue((bool)value);
var opt = HolderOption as ModdedToggleOption;
opt?.SetValue((bool)value);
}
/// <inheritdoc />
public override object GetValue()
{
var toggleOpt = HolderOption as ModdedToggleOption;
return toggleOpt.Value;
if (HolderOption is ModdedToggleOption opt)
{
return opt.Value;
}
throw new InvalidOperationException($"Holder option for {Title} is not a ModdedToggleOption.");
}
}
}
+11 -15
View File
@@ -3,21 +3,17 @@ using System.Linq;
namespace MiraAPI.GameOptions;
/// <summary>
/// Singleton for option groups.
/// </summary>
/// <typeparam name="T">The option group type.</typeparam>
public class OptionGroupSingleton<T> where T : AbstractOptionGroup
{
private static T _instance;
private static T? _instance;
public static T Instance
{
get => _instance ??= ModdedOptionsManager.Groups.OfType<T>().Single();
set
{
if (_instance != null)
{
throw new InvalidOperationException($"Instance for {typeof(T)} is already set");
}
_instance = value;
}
}
}
/// <summary>
/// Gets the instance of the option group.
/// </summary>
/// <exception cref="InvalidOperationException">Can't</exception>
public static T Instance => _instance ??= ModdedOptionsManager.Groups.OfType<T>().Single();
}
@@ -2,18 +2,33 @@
using Reactor.Localization.Utilities;
using System;
using System.Linq;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using UnityEngine;
using Object = UnityEngine.Object;
namespace MiraAPI.GameOptions.OptionTypes;
/// <summary>
/// An option for selecting an enum value.
/// </summary>
public class ModdedEnumOption : ModdedOption<int>
{
public string[] Values { get; }
/// <summary>
/// Gets the string values of the enum.
/// </summary>
public string[]? Values { get; }
public ModdedEnumOption(string title, int defaultValue, Type enumType, string[] values = null, Type roleType = null) : base(title, defaultValue, roleType)
/// <summary>
/// Initializes a new instance of the <see cref="ModdedEnumOption"/> class.
/// </summary>
/// <param name="title">The title of the option.</param>
/// <param name="defaultValue">The default value as an int.</param>
/// <param name="enumType">The Enum type.</param>
/// <param name="values">An option list of string values to use in place of the enum name.</param>
/// <param name="roleType">An optional role type to specify for a specific role.</param>
public ModdedEnumOption(string title, int defaultValue, Type enumType, string[]? values = null, Type? roleType = null) : base(title, defaultValue, roleType)
{
Values = values is null ? Enum.GetNames(enumType) : values;
Values = values ?? Enum.GetNames(enumType);
Data = ScriptableObject.CreateInstance<StringGameSetting>();
var data = (StringGameSetting)Data;
@@ -26,6 +41,7 @@ public class ModdedEnumOption : ModdedOption<int>
data.Index = Value;
}
/// <inheritdoc />
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
{
var stringOption = Object.Instantiate(stringOpt, container);
@@ -35,7 +51,7 @@ public class ModdedEnumOption : ModdedOption<int>
// SetUpFromData method doesnt work correctly so we must set the values manually
stringOption.Title = StringName;
stringOption.Values = ((StringGameSetting)Data).Values;
stringOption.Values = (Data as StringGameSetting)?.Values ?? new Il2CppStructArray<StringNames>(0);
stringOption.Value = Value;
OptionBehaviour = stringOption;
@@ -43,38 +59,42 @@ public class ModdedEnumOption : ModdedOption<int>
return stringOption;
}
/// <inheritdoc />
public override float GetFloatData()
{
return Value;
}
/// <inheritdoc />
public override NetData GetNetData()
{
return new NetData(Id, BitConverter.GetBytes(Value));
}
/// <inheritdoc />
public override void HandleNetData(byte[] data)
{
SetValue(BitConverter.ToInt32(data));
}
/// <inheritdoc />
public override int GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour)
{
return optionBehaviour.GetInt();
}
/// <inheritdoc />
protected override void OnValueChanged(int newValue)
{
DestroyableSingleton<HudManager>.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(newValue), false);
DestroyableSingleton<HudManager>.Instance.Notifier.AddSettingsChangeMessage(StringName, Data?.GetValueString(newValue), false);
if (!OptionBehaviour)
{
return;
}
var opt = OptionBehaviour as StringOption;
if (opt)
if (OptionBehaviour is StringOption opt)
{
opt.Value = newValue;
}
}
}
}
@@ -7,19 +7,56 @@ using Object = UnityEngine.Object;
namespace MiraAPI.GameOptions.OptionTypes;
/// <summary>
/// Represents a modded number option.
/// </summary>
public class ModdedNumberOption : ModdedOption<float>
{
/// <summary>
/// Gets the minimum value of the option.
/// </summary>
public float Min { get; }
/// <summary>
/// Gets the maximum value of the option.
/// </summary>
public float Max { get; }
/// <summary>
/// Gets the increment value of the option.
/// </summary>
public float Increment { get; }
/// <summary>
/// Gets the suffix type of the option.
/// </summary>
public MiraNumberSuffixes SuffixType { get; }
/// <summary>
/// Gets a value indicating whether zero is infinity.
/// </summary>
public bool ZeroInfinity { get; }
public ModdedNumberOption(string title, float defaultValue, float min, float max, float increment, MiraNumberSuffixes suffixType, bool zeroInfinity = false, Type roleType = null) : base(title, defaultValue, roleType)
/// <summary>
/// Initializes a new instance of the <see cref="ModdedNumberOption"/> class.
/// </summary>
/// <param name="title">The title of the option.</param>
/// <param name="defaultValue">The default value as a float.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <param name="increment">The increment.</param>
/// <param name="suffixType">The suffix type.</param>
/// <param name="zeroInfinity">Whether zero is infinity or not.</param>
/// <param name="roleType">An optional role type.</param>
public ModdedNumberOption(
string title,
float defaultValue,
float min,
float max,
float increment,
MiraNumberSuffixes suffixType,
bool zeroInfinity = false,
Type? roleType = null) : base(title, defaultValue, roleType)
{
Min = min;
Max = max;
@@ -37,13 +74,18 @@ public class ModdedNumberOption : ModdedOption<float>
data.Value = Value;
data.Increment = Increment;
data.ValidRange = new FloatRange(Min, Max);
data.FormatString = Increment % 1 == 0 && Value % 1 == 0 && Min % 1 == 0 && Max % 1 == 0 ? "0" : "0.0";
data.FormatString = Increment % 1 == 0 && Value % 1 == 0 && Min % 1 == 0 && Max % 1 == 0 ? "0" : "0.0"; // not sure if the == checks will work since this is floats but we'll find out
data.ZeroIsInfinity = ZeroInfinity;
data.SuffixType = (NumberSuffixes)SuffixType;
data.OptionName = FloatOptionNames.Invalid;
}
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
/// <inheritdoc />
public override OptionBehaviour CreateOption(
ToggleOption toggleOpt,
NumberOption numberOpt,
StringOption stringOpt,
Transform container)
{
var numberOption = Object.Instantiate(numberOpt, Vector3.zero, Quaternion.identity, container);
@@ -54,51 +96,52 @@ public class ModdedNumberOption : ModdedOption<float>
numberOption.Value = Value;
numberOption.Increment = Increment;
numberOption.ValidRange = new FloatRange(Min, Max);
numberOption.FormatString = ((FloatGameSetting)Data).FormatString;
numberOption.FormatString = (Data as FloatGameSetting)?.FormatString ?? "0.0";
numberOption.ZeroIsInfinity = ZeroInfinity;
numberOption.SuffixType = (NumberSuffixes)SuffixType;
numberOption.floatOptionName = FloatOptionNames.Invalid;
OptionBehaviour = numberOption;
return numberOption;
}
/// <inheritdoc />
public override float GetFloatData()
{
return Value;
}
/// <inheritdoc />
public override NetData GetNetData()
{
return new NetData(Id, BitConverter.GetBytes(Value));
}
/// <inheritdoc />
public override void HandleNetData(byte[] data)
{
SetValue(BitConverter.ToSingle(data));
}
/// <inheritdoc />
public override float GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour)
{
return Mathf.Clamp(optionBehaviour.GetFloat(), Min, Max);
}
/// <inheritdoc />
protected override void OnValueChanged(float newValue)
{
Value = Mathf.Clamp(newValue, Min, Max);
DestroyableSingleton<HudManager>.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(Value), false);
DestroyableSingleton<HudManager>.Instance.Notifier.AddSettingsChangeMessage(
StringName,
Data?.GetValueString(Value),
false);
if (!OptionBehaviour)
if (OptionBehaviour is NumberOption opt)
{
return;
}
var opt = OptionBehaviour as NumberOption;
if (opt)
{
opt.Value = newValue;
opt.Value = Value;
}
}
}
}
@@ -1,77 +0,0 @@
using Reactor.Localization.Utilities;
using System;
using System.Linq;
using MiraAPI.Networking;
using UnityEngine;
using Object = UnityEngine.Object;
namespace MiraAPI.GameOptions.OptionTypes;
public class ModdedStringOption : ModdedOption<int>
{
public string[] Values { get; }
public ModdedStringOption(string title, int defaultValue, string[] values, Type roleType=null) : base(title, defaultValue, roleType)
{
Values = values;
Data = ScriptableObject.CreateInstance<StringGameSetting>();
var data = (StringGameSetting)Data;
data.Title = StringName;
data.Type = global::OptionTypes.String;
data.Values = Values.Select(CustomStringName.CreateAndRegister).ToArray();
data.Index = Value;
}
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
{
var stringOption = Object.Instantiate(stringOpt, container);
stringOption.SetUpFromData(Data, 20);
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
// SetUpFromData method doesnt work correctly so we must set the values manually
stringOption.Title = StringName;
stringOption.Values = ((StringGameSetting)Data).Values;
stringOption.Value = Value;
OptionBehaviour = stringOption;
return stringOption;
}
public override float GetFloatData()
{
return Value;
}
public override NetData GetNetData()
{
return new NetData(Id, BitConverter.GetBytes(Value));
}
public override void HandleNetData(byte[] data)
{
SetValue(BitConverter.ToInt32(data));
}
public override int GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour)
{
return optionBehaviour.GetInt();
}
protected override void OnValueChanged(int newValue)
{
DestroyableSingleton<HudManager>.Instance.Notifier.AddSettingsChangeMessage(StringName, Data.GetValueString(newValue), false);
if (!OptionBehaviour)
{
return;
}
var opt = OptionBehaviour as StringOption;
if (opt)
{
opt.Value = newValue;
}
}
}
@@ -5,9 +5,18 @@ using Object = UnityEngine.Object;
namespace MiraAPI.GameOptions.OptionTypes;
/// <summary>
/// A modded toggle option.
/// </summary>
public class ModdedToggleOption : ModdedOption<bool>
{
public ModdedToggleOption(string title, bool defaultValue, Type roleType = null) : base(title, defaultValue, roleType)
/// <summary>
/// Initializes a new instance of the <see cref="ModdedToggleOption"/> class.
/// </summary>
/// <param name="title">The option title.</param>
/// <param name="defaultValue">The default value.</param>
/// <param name="roleType">An optional role type.</param>
public ModdedToggleOption(string title, bool defaultValue, Type? roleType = null) : base(title, defaultValue, roleType)
{
Data = ScriptableObject.CreateInstance<CheckboxGameSetting>();
@@ -16,6 +25,7 @@ public class ModdedToggleOption : ModdedOption<bool>
data.Type = global::OptionTypes.Checkbox;
}
/// <inheritdoc />
public override OptionBehaviour CreateOption(ToggleOption toggleOpt, NumberOption numberOpt, StringOption stringOpt, Transform container)
{
var toggleOption = Object.Instantiate(toggleOpt, Vector3.zero, Quaternion.identity, container);
@@ -32,26 +42,31 @@ public class ModdedToggleOption : ModdedOption<bool>
return toggleOption;
}
/// <inheritdoc />
public override float GetFloatData()
{
return Value ? 1 : 0;
}
/// <inheritdoc />
public override NetData GetNetData()
{
return new NetData(Id, BitConverter.GetBytes(Value));
}
/// <inheritdoc />
public override void HandleNetData(byte[] data)
{
SetValue(BitConverter.ToBoolean(data));
}
/// <inheritdoc />
public override bool GetValueFromOptionBehaviour(OptionBehaviour optionBehaviour)
{
return optionBehaviour.GetBool();
}
/// <inheritdoc />
protected override void OnValueChanged(bool newValue)
{
DestroyableSingleton<HudManager>.Instance.Notifier.AddSettingsChangeMessage(StringName, newValue ? "On" : "Off", false);
@@ -60,10 +75,9 @@ public class ModdedToggleOption : ModdedOption<bool>
return;
}
var toggleOpt = OptionBehaviour as ToggleOption;
if (toggleOpt)
if (OptionBehaviour is ToggleOption toggleOpt)
{
toggleOpt.CheckMark.enabled = newValue;
}
}
}
}
+4 -22
View File
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using System.Linq;
namespace MiraAPI.Hud;
@@ -12,24 +11,7 @@ public static class CustomButtonSingleton<T> where T : CustomActionButton
private static T? _instance;
/// <summary>
/// Gets or sets instance of the button.
/// Gets the instance of the button.
/// </summary>
public static T Instance
{
get => _instance ??= CustomButtonManager.CustomButtons.OfType<T>().Single();
set
{
if (_instance == value)
{
return;
}
if (_instance != null)
{
throw new InvalidOperationException($"Instance for {typeof(T)} is already set");
}
_instance = value;
}
}
}
public static T Instance => _instance ??= CustomButtonManager.CustomButtons.OfType<T>().Single();
}
@@ -1,5 +1,4 @@
using HarmonyLib;
using MiraAPI.Colors;
using MiraAPI.Roles;
namespace MiraAPI.Patches.Roles;
+3 -6
View File
@@ -118,7 +118,7 @@ public float SussyLevel { get; set; } = 4f; // You can set a default value here.
Here are the available Option Attributes and their signatures:
```csharp
ModdedEnumOption(string name, Type enumType, Type roleType = null)
ModdedEnumOption(string name, Type enumType, string[]? values = null, Type? roleType = null)
ModdedNumberOption(
string name,
@@ -127,11 +127,9 @@ ModdedNumberOption(
float increment=1
NumberSuffixes suffixType = NumberSuffixes.None,
bool zeroInfinity = false,
Type roleType = null)
ModdedStringOption(string title, string[] values, Type roleType = null)
Type? roleType = null)
ModdedToggleOption(string name, Type roleType = null)
ModdedToggleOption(string name, Type? roleType = null)
```
### ModdedOption Properties
@@ -144,7 +142,6 @@ public ModdedToggleOption YeezusAbility { get; } = new ModdedToggleOption("Yeezu
Here is a full list of ModdedOption classes you can use:
- `ModdedEnumOption`
- `ModdedNumberOption`
- `ModdedStringOption`
- `ModdedToggleOption`
To see a full example of an options class, see [this file](https://github.com/All-Of-Us-Mods/MiraAPI/blob/master/MiraAPI.Example/Options/ExampleOptions.cs).