more stuff

This commit is contained in:
Az committed 2026-10-15 20:46:41 -04:00
1 parent b074fdc330
commit 04b7701b79
23 files changed
+283 -124

No files matched your search

+7 -4
View File
@@ -27,19 +27,22 @@ public class ExampleOptions : AbstractOptionGroup
[ModdedOptionVisibility(nameof(NumberOptVisibility))] // Can also target static methods
public float NumberOpt { get; set; } = 4f;
[ModdedNumberOption("options.exampleOptions1.numberOpt", min: 0, max: 10, suffixType: MiraNumberSuffixes.Distance)]
public int NumberOpt2 { get; set; } = 4; // Can also be int!
[ModdedEnumOption("options.exampleOptions1.bestApi", typeof(Api), ["Mira API", "Mitochondria", "Reactor"])]
public Api BestApi { get; set; } = Api.MiraAPI;
[ModdedEnumOption<Api>("options.exampleOptions1.worstApi", ["Mira API", "Mitochondria", "Reactor"])]
// These three can target both instance and static methods
[ModdedOptionGetter(nameof(GetApi))] // Can also automatically resolve to {Option Name}Getter
[ModdedOptionSetter(nameof(SetApi))] // Can also automatically resolve to {Option Name}Setter
[ModdedOptionChanged(nameof(ApiChanged))] // Can also automatically resolve to {Option Name}Changed
public Api BestApi { get; set; } = Api.MiraAPI;
[ModdedEnumOption<Api>("options.exampleOptions1.worstApi", ["Mira API", "Mitochondria", "Reactor"])]
public Api WorstApi { get; set; } = Api.MiraAPI;
[ModdedEnumOptionList<ValueState>("Value State {0}", ["None", "Primary", "Secondary"])]
public List<ValueState> ValueStates { get; } =
public List<ValueState> ValueStates { get; set; } =
[ValueState.Primary, ValueState.Secondary, ValueState.None, ValueState.None, ValueState.None];
public bool ToggleOpt1Visibility()
@@ -47,6 +47,7 @@ Eliminate every other faction.</string>
<string name="options.exampleOptions1.toggleOpt2">Toggle Opt 2</string>
<string name="options.exampleOptions1.numberOpt">Number Opt</string>
<string name="options.exampleOptions1.bestApi">Best API</string>
<string name="options.exampleOptions1.worstApi">Worst API</string>
<string name="options.exampleOptions2">Example Options 2</string>
<string name="options.exampleOptions2.youMustChoseAPlayer">YOU MUST CHOSE A PLAYER</string>
<string name="options.exampleOptions2.ehWhatever">Eh whatever</string>
@@ -32,7 +32,7 @@ public class ModdedEnumOptionAttribute(string title, Type enumType, string[]? va
{
return HolderOption is ModdedEnumOption opt
? Enum.ToObject(enumType, opt.Value)
: throw new InvalidOperationException($"HolderOption for option \"{Title}\" with EnumType ${enumType.FullName} is not a ModdedEnumOption");
: throw new InvalidOperationException($"HolderOption for option \"{Title}\" with EnumType {enumType.FullName} is not a ModdedEnumOption");
}
}
@@ -65,6 +65,6 @@ public class ModdedEnumOptionAttribute<T>(string title, string[]? values = null)
{
return HolderOption is ModdedEnumOption<T> opt
? opt.Value
: throw new InvalidOperationException($"HolderOption for option \"{Title}\" with EnumType ${typeof(T).FullName} is not a ModdedEnumOption");
: throw new InvalidOperationException($"HolderOption for option \"{Title}\" with EnumType {typeof(T).FullName} is not a ModdedEnumOption<{typeof(T).Name}>");
}
}
@@ -28,9 +28,16 @@ public class ModdedNumberOptionAttribute(
{
internal override IModdedOption CreateOption(object? value, PropertyInfo property)
{
var final = value switch
{
null => min + increment,
int integer => integer,
_ => (float)value,
};
return new ModdedNumberOption(
Title,
(float)(value ?? min + increment),
final,
min,
max,
increment,
@@ -42,15 +49,28 @@ public class ModdedNumberOptionAttribute(
/// <inheritdoc />
public override void SetValue(object value)
{
var opt = HolderOption as ModdedNumberOption;
opt?.SetValue((float)value);
if (HolderOption is not ModdedNumberOption opt)
return;
var final = value switch
{
int integer => integer,
_ => (float)value,
};
opt.SetValue(final);
}
/// <inheritdoc />
public override object GetValue()
{
return HolderOption is ModdedNumberOption opt
? (object)opt.Value
: throw new InvalidOperationException($"HolderOption for option \"{Title}\" is not a ModdedNumberOption");
if (HolderOption is not ModdedNumberOption opt)
throw new InvalidOperationException($"HolderOption for option \"{Title}\" is not a ModdedNumberOption");
var value = opt.Value;
if (ValueType == typeof(int))
return (int)Math.Round(value);
return value;
}
}
@@ -13,6 +13,7 @@ namespace MiraAPI.GameOptions.Attributes;
public abstract class ModdedOptionAttribute(string title, Type? roleType = null, Type? modeType = null) : PropertyOptionAttribute
{
internal IModdedOption? HolderOption { get; set; }
internal Type ValueType { get; set; }
/// <summary>
/// Gets the title of the option.
@@ -0,0 +1,49 @@
using System;
using System.Reflection;
using MiraAPI.GameOptions.OptionTypes;
namespace MiraAPI.GameOptions.Attributes;
/// <summary>
/// Attribute for a <see cref="ModdedPlayerOption"/>.
/// </summary>
/// <param name="title">The title of the option.</param>
/// <param name="allowNone">Whether the option includes a none option. If None is selected, value will return -1.</param>
[AttributeUsage(AttributeTargets.Property)]
public class ModdedPlayerOptionAttribute(
string title,
bool allowNone = true)
: ModdedOptionAttribute(title)
{
internal override IModdedOption? CreateOption(object? value, PropertyInfo property)
{
var option = new ModdedPlayerOption(Title, allowNone);
return option;
}
/// <inheritdoc />
public override object GetValue()
{
if (HolderOption is not ModdedPlayerOption opt)
throw new InvalidOperationException($"Holder option for {Title} is not a ModdedPlayerOption.");
if (ValueType == typeof(int))
return opt.Value;
return opt.SelectedPlayer!;
}
/// <inheritdoc />
public override void SetValue(object value)
{
if (HolderOption is not ModdedPlayerOption opt)
return;
var final = value switch
{
NetworkedPlayerInfo info => opt.Values.IndexOf(info),
_ => (int)value,
};
opt?.SetValue(final);
}
}
@@ -25,7 +25,7 @@ public class ModdedStringOptionAttribute(
public override object GetValue()
{
return HolderOption is ModdedStringOption opt
? (object)opt.Value
? opt.Value
: throw new InvalidOperationException($"Holder option for {Title} is not a ModdedStringOption.");
}
@@ -28,7 +28,7 @@ public class ModdedToggleOptionAttribute(string title) : ModdedOptionAttribute(t
public override object GetValue()
{
return HolderOption is ModdedToggleOption opt
? (object)opt.Value
? opt.Value
: throw new InvalidOperationException($"Holder option for {Title} is not a ModdedToggleOption.");
}
}
@@ -34,7 +34,7 @@ public class ModdedEnumOptionListAttribute(string title, Type enumType, string[]
{
return HolderOptionList?[idx] is ModdedEnumOption opt
? Enum.ToObject(enumType, opt.Value)
: throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" with EnumType ${enumType.FullName} is not a ModdedEnumOption");
: throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" with EnumType {enumType.FullName} is not a ModdedEnumOption");
}
}
@@ -68,6 +68,6 @@ public class ModdedEnumOptionListAttribute<T>(string title, string[]? values = n
{
return HolderOptionList?[idx] is ModdedEnumOption<T> opt
? opt.Value
: throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" with EnumType ${typeof(T).FullName} is not a ModdedEnumOption");
: throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" with EnumType {typeof(T).FullName} is not a ModdedEnumOption<{typeof(T).FullName}>");
}
}
@@ -31,9 +31,16 @@ public class ModdedNumberOptionListAttribute(
{
return new ModdedOptionList<ModdedNumberOption>(value.Count, idx =>
{
var final = value[idx] switch
{
null => min + increment,
int integer => integer,
_ => (float)value[idx]!,
};
return new(
GetFormattedTitle(idx),
(float)(value[idx] ?? min + increment),
final,
min,
max,
increment,
@@ -46,15 +53,28 @@ public class ModdedNumberOptionListAttribute(
/// <inheritdoc />
public override void SetValue(int idx, object value)
{
var opt = HolderOptionList?[idx] as ModdedNumberOption;
opt?.SetValue((float)value);
if (HolderOptionList?[idx] is not ModdedNumberOption opt)
return;
var final = value switch
{
int integer => integer,
_ => (float)value,
};
opt.SetValue(final);
}
/// <inheritdoc />
public override object GetValue(int idx)
{
return HolderOptionList?[idx] is ModdedNumberOption opt
? (object)opt.Value
: throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" is not a ModdedNumberOption");
if (HolderOptionList?[idx] is not ModdedNumberOption opt)
throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" is not a ModdedNumberOption");
var value = opt.Value;
if (ValueType == typeof(int))
return (int)Math.Round(value);
return value;
}
}
@@ -3,6 +3,7 @@ using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text.RegularExpressions;
using MiraAPI.Translation;
namespace MiraAPI.GameOptions.Attributes;
@@ -14,8 +15,8 @@ namespace MiraAPI.GameOptions.Attributes;
public abstract class ModdedOptionListAttribute(string title) : PropertyOptionAttribute
{
internal IModdedOptionList? HolderOptionList { get; set; }
internal object? Value { get; set; }
internal IList? Value { get; set; }
internal Type ValueType { get; set; }
/// <summary>
/// Gets the title of the options.
@@ -31,16 +32,16 @@ public abstract class ModdedOptionListAttribute(string title) : PropertyOptionAt
/// <param name="value">The new values as an object.</param>
public override void SetValue(object value)
{
Value = value;
var list = (IList)value;
if (list.Count != HolderOptionList!.Count)
Value = (IList)value;
if (Value.Count != HolderOptionList!.Count)
{
throw new InvalidOperationException($"Value set to option list cannot change the list's length.");
}
for (int i = 0; i < list.Count; i++)
for (int i = 0; i < Value.Count; i++)
{
SetValue(i, list[i]!);
SetValue(i, Value[i]!);
}
}
@@ -77,18 +78,19 @@ public abstract class ModdedOptionListAttribute(string title) : PropertyOptionAt
[SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "I don't even know if this is worth it.")]
protected string GetFormattedTitle(int index)
{
Match match = Regex.Match(Title, @"\{(\d+)(?::[^}]+)?\}", default, Regex.InfiniteMatchTimeout);
var match = Regex.Match(Title.Translate(), @"\{(\d+)(?::[^}]+)?\}", default, Regex.InfiniteMatchTimeout);
if (match.Success)
if (!match.Success)
{
if (match.Groups.Count == 1 && match.Groups[0].Value == "0")
{
return string.Format(Title, index);
}
Error("ModdedOptionList Title cannot contain more than the first parameter for formatting.");
return Title + index;
}
if (match.Value == "{0}" && !match.NextMatch().Success)
{
return string.Format(Title, index);
}
Error($"ModdedOptionList Title of {Title} cannot contain more than the first parameter for formatting.");
return Title + index;
}
}
@@ -0,0 +1,54 @@
using System;
using System.Collections;
using System.Reflection;
using MiraAPI.GameOptions.OptionTypes;
namespace MiraAPI.GameOptions.Attributes;
/// <summary>
/// Attribute for creating a list of player options.
/// </summary>
/// <param name="title">The option title.</param>
/// <param name="allowNone">Whether the option includes a none option. If None is selected, value will return -1.</param>
[AttributeUsage(AttributeTargets.Property)]
public class ModdedPlayerOptionListAttribute(
string title,
bool allowNone = true)
: ModdedOptionListAttribute(title)
{
internal override IModdedOptionList CreateOptionList(IList value, PropertyInfo property)
{
return new ModdedOptionList<ModdedPlayerOption>(value.Count, idx =>
{
return new(GetFormattedTitle(idx), allowNone);
});
}
/// <inheritdoc />
public override void SetValue(int idx, object value)
{
if (HolderOptionList?[idx] is not ModdedPlayerOption opt)
return;
var final = value switch
{
NetworkedPlayerInfo info => opt.Values.IndexOf(info),
_ => (int)value,
};
opt?.SetValue(final);
}
/// <inheritdoc />
public override object GetValue(int idx)
{
if (HolderOptionList?[idx] is not ModdedNumberOption opt)
throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" is not a ModdedNumberOption");
var value = opt.Value;
if (ValueType == typeof(int))
return (int)Math.Round(value);
return value;
}
}
@@ -36,7 +36,7 @@ public class ModdedStringOptionListAttribute(
public override object GetValue(int idx)
{
return HolderOptionList?[idx] is ModdedStringOption opt
? (object)opt.Value
? opt.Value
: throw new InvalidOperationException($"HolderOption for option \"{GetFormattedTitle(idx)}\" is not a ModdedStringOption");
}
}
@@ -30,7 +30,7 @@ public class ModdedToggleOptionListAttribute(string title) : ModdedOptionListAtt
public override object GetValue(int idx)
{
return HolderOptionList?[idx] is ModdedToggleOption opt
? (object)opt.Value
? opt.Value
: throw new InvalidOperationException($"Holder option for {GetFormattedTitle(idx)} is not a ModdedToggleOption.");
}
}
+38 -24
View File
@@ -62,14 +62,14 @@ public static class ModdedOptionsManager
internal static bool RegisterGroup(Type type)
{
if (Activator.CreateInstance(type) is not AbstractOptionGroup group)
if (TypeToGroup.ContainsKey(type))
{
Error($"Group {type.Name} already exists.");
return false;
}
if (TypeToGroup.ContainsKey(type))
if (Activator.CreateInstance(type) is not AbstractOptionGroup group)
{
Logger<MiraApiPlugin>.Error($"Group {type.Name} already exists.");
return false;
}
@@ -79,17 +79,17 @@ public static class ModdedOptionsManager
internal static bool RegisterGroup(Type type, MiraPluginInfo pluginInfo)
{
if (Activator.CreateInstance(type) is not AbstractOptionGroup group)
{
return false;
}
if (TypeToGroup.ContainsKey(type))
{
Error($"Group {type.Name} already exists.");
return false;
}
if (Activator.CreateInstance(type) is not AbstractOptionGroup group)
{
return false;
}
if (typeof(AbstractGameMode).IsAssignableFrom(group.OptionableType))
{
if (GameModeOptionGroups.TryGetValue(group.OptionableType, out var oldList))
@@ -117,7 +117,7 @@ public static class ModdedOptionsManager
Groups.Add(group);
TypeToGroup.Add(type, group);
typeof(OptionGroupSingleton<>).MakeGenericType(type)
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)! // Message suppression points to here
.GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)!
.SetValue(null, group);
}
@@ -164,16 +164,21 @@ public static class ModdedOptionsManager
return;
}
var setterOriginal = property.GetSetMethod(true);
var setterPatch = typeof(ModdedOptionsManager).GetMethod(nameof(PropertySetterPatch));
PluginSingleton<MiraApiPlugin>.Instance.Harmony.Patch(setterOriginal, postfix: new HarmonyMethod(setterPatch));
var getterOriginal = property.GetGetMethod(true);
var getterPatch = typeof(ModdedOptionsManager).GetMethod(nameof(PropertyGetterPatch));
PluginSingleton<MiraApiPlugin>.Instance.Harmony.Patch(getterOriginal, prefix: new HarmonyMethod(getterPatch));
var setterOriginal = property.GetSetMethod(true);
if (setterOriginal != null)
{
var setterPatch = typeof(ModdedOptionsManager).GetMethod(nameof(PropertySetterPatch));
PluginSingleton<MiraApiPlugin>.Instance.Harmony.Patch(setterOriginal, postfix: new HarmonyMethod(setterPatch));
}
OptionAttributes.Add(property, attribute);
attribute.HolderOption = option;
attribute.ValueType = property.PropertyType;
var visibilityAttr = property.GetCustomAttribute<ModdedOptionVisibilityAttribute>();
var visibilityFunc = visibilityAttr?.GetVisibility(group, property);
@@ -220,9 +225,9 @@ public static class ModdedOptionsManager
return;
}
Func<int, string> configName = optionList.ConfigName ?? (i => property.Name + (i + 1));
var configName = optionList.ConfigName ?? (i => property.Name + (i + 1));
for (int i = 0; i < optionList.Count; i++)
for (var i = 0; i < optionList.Count; i++)
{
RegisterOption(optionList[i], group, configName(i), pluginInfo);
}
@@ -269,32 +274,41 @@ public static class ModdedOptionsManager
return;
}
var setterOriginal = property.GetSetMethod(true);
var setterPatch = typeof(ModdedOptionsManager).GetMethod(nameof(PropertySetterPatch));
PluginSingleton<MiraApiPlugin>.Instance.Harmony.Patch(setterOriginal, postfix: new HarmonyMethod(setterPatch));
var getterOriginal = property.GetGetMethod(true);
var getterPatch = typeof(ModdedOptionsManager).GetMethod(nameof(PropertyGetterPatch));
PluginSingleton<MiraApiPlugin>.Instance.Harmony.Patch(getterOriginal, prefix: new HarmonyMethod(getterPatch));
var setterOriginal = property.GetSetMethod(true);
if (setterOriginal != null)
{
var setterPatch = typeof(ModdedOptionsManager).GetMethod(nameof(PropertySetterPatch));
PluginSingleton<MiraApiPlugin>.Instance.Harmony.Patch(setterOriginal, postfix: new HarmonyMethod(setterPatch));
}
var listType = propertyList.GetType();
if (PatchedListTypes.Add(listType))
{
var listIndex = listType.GetProperty("Item")!;
var listSetterOriginal = listIndex.GetSetMethod(true);
var listSetterPatch = typeof(ModdedOptionsManager).GetMethod(nameof(PropertyListSetterPatch));
PluginSingleton<MiraApiPlugin>.Instance.Harmony.Patch(listSetterOriginal, postfix: new HarmonyMethod(listSetterPatch));
var listGetterOriginal = listIndex.GetGetMethod(true);
var listGetterPatch = typeof(ModdedOptionsManager).GetMethod(nameof(PropertyListGetterPatch));
PluginSingleton<MiraApiPlugin>.Instance.Harmony.Patch(listGetterOriginal, prefix: new HarmonyMethod(listGetterPatch));
var listSetterOriginal = listIndex.GetSetMethod(true);
if (listSetterOriginal != null)
{
var listSetterPatch = typeof(ModdedOptionsManager).GetMethod(nameof(PropertyListSetterPatch));
PluginSingleton<MiraApiPlugin>.Instance.Harmony.Patch(listSetterOriginal, postfix: new HarmonyMethod(listSetterPatch));
}
}
OptionAttributes.Add(property, attribute);
attribute.HolderOptionList = optionList;
attribute.Value = propertyVal;
attribute.Value = (IList)propertyVal;
attribute.ValueType = listType.GetGenericArguments()[0];
var valueType = property.PropertyType.GetGenericArguments()[0];
@@ -50,7 +50,7 @@ public class ModdedEnumOption : ModdedOption<int>
$"{ParentMod!.OptionsTitleText}.EnumOption.{TranslationController.Instance.GetString(StringName)}";
stringOption.SetUpFromData(Data, 20);
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
stringOption.OnValueChanged = (Action<OptionBehaviour>)ValueChanged;
// Changing the button text to make them more distinct from number options
stringOption.MinusBtn.ChangeButtonText("<");
@@ -153,7 +153,7 @@ public class ModdedEnumOption<T> : ModdedOption<T>
$"{ParentMod!.OptionsTitleText}.EnumOption.{TranslationController.Instance.GetString(StringName)}";
stringOption.SetUpFromData(Data, 20);
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
stringOption.OnValueChanged = (Action<OptionBehaviour>)ValueChanged;
// Changing the button text to make them more distinct from number options
stringOption.MinusBtn.ChangeButtonText("<");
@@ -78,8 +78,36 @@ public class ModdedNumberOption : ModdedOption<float>
string? formatString = null,
bool halfIncrements = false,
bool includeInPreset = true)
: this(title, defaultValue, min, max, increment, suffixType, zeroBehavior, negativeBehavior, halfIncrements, formatString, includeInPreset)
: base(title, defaultValue, includeInPreset)
{
Min = min;
Max = max;
Increment = increment;
SuffixType = suffixType;
ZeroWordValue = zeroBehavior;
ShiftIncrement = halfIncrements;
NegativeWordValue = negativeBehavior;
Value = Mathf.Clamp(defaultValue, min, max);
var data = ScriptableObject.CreateInstance<FloatGameSetting>();
data.Type = global::OptionTypes.Float;
data.Title = StringName;
data.Value = Value;
data.Increment = Increment;
data.ValidRange = new FloatRange(Min, Max);
data.FormatString = formatString ??
(defaultValue.IsInteger() &&
Increment.IsInteger() &&
Value.IsInteger() &&
Min.IsInteger() &&
Max.IsInteger() ? "0" : "0.0");
data.ZeroIsInfinity = ZeroInfinity;
data.SuffixType = (NumberSuffixes)SuffixType;
data.OptionName = FloatOptionNames.Invalid;
Data = data;
}
/// <summary>
@@ -104,54 +132,10 @@ public class ModdedNumberOption : ModdedOption<float>
string? formatString = null,
bool zeroInfinity = false,
bool includeInPreset = true)
: this(title, defaultValue, min, max, increment, suffixType, zeroInfinity ? "∞" : "#", "#", increment == 1f, formatString, includeInPreset)
: this(title, defaultValue, min, max, increment, zeroInfinity ? "∞" : "#", "#", suffixType, formatString, increment == 1f, includeInPreset)
{
}
private ModdedNumberOption(
string title,
float defaultValue,
float min,
float max,
float increment,
MiraNumberSuffixes suffixType,
string zeroBehavior,
string negativeBehavior,
bool shiftIncrement,
string? formatString,
bool includeInPreset)
: base(title, defaultValue, includeInPreset)
{
Min = min;
Max = max;
Increment = increment;
SuffixType = suffixType;
ZeroWordValue = zeroBehavior;
ShiftIncrement = shiftIncrement;
NegativeWordValue = negativeBehavior;
Value = Mathf.Clamp(defaultValue, min, max);
var data = ScriptableObject.CreateInstance<FloatGameSetting>();
data.Type = global::OptionTypes.Float;
data.Title = StringName;
data.Value = Value;
data.Increment = Increment;
data.ValidRange = new FloatRange(Min, Max);
data.FormatString = formatString ??
(defaultValue.IsInteger() &&
Increment.IsInteger() &&
Value.IsInteger() &&
Min.IsInteger() &&
Max.IsInteger() ? "0" : "0.0");
data.ZeroIsInfinity = ZeroInfinity;
data.SuffixType = (NumberSuffixes)SuffixType;
data.OptionName = FloatOptionNames.Invalid;
Data = data;
}
/// <inheritdoc />
public override OptionBehaviour CreateOption(
ToggleOption toggleOpt,
@@ -29,6 +29,11 @@ public class ModdedPlayerOption : ModdedOption<int>
/// </summary>
public bool AllowNone { get; set; }
/// <summary>
/// Gets the player selected by this option. May be <c>null</c> if allowed to have <c>None</c> as an option.
/// </summary>
public NetworkedPlayerInfo? SelectedPlayer => Value == -1 ? null : Values[Value];
/// <summary>
/// Initializes a new instance of the <see cref="ModdedPlayerOption"/> class.
/// </summary>
@@ -64,7 +69,7 @@ public class ModdedPlayerOption : ModdedOption<int>
Values = GetFilteredPlayers();
playerOption.SetUpFromData(Data, 20);
playerOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
playerOption.OnValueChanged = (Action<OptionBehaviour>)ValueChanged;
playerOption.Title = StringName;
playerOption.TitleText.text = Title.Translate();
@@ -124,7 +124,7 @@ public class ModdedStringOption : ModdedOption<string>
$"{ParentMod!.OptionsTitleText}.StringOption.{TranslationController.Instance.GetString(StringName)}";
stringOption.SetUpFromData(Data, 20);
stringOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
stringOption.OnValueChanged = (Action<OptionBehaviour>)ValueChanged;
// Changing the button text to make them more distinct from number options
stringOption.MinusBtn.ChangeButtonText("<");
@@ -11,6 +11,11 @@ namespace MiraAPI.GameOptions.OptionTypes;
/// </summary>
public class ModdedToggleOption : ModdedOption<bool>
{
/// <summary>
/// Gets or sets the delegate that dictates how a toggle option's value is displayed.
/// </summary>
public Func<bool, string> DisplayValue { get; set; } = value => value ? "On" : "Off";
/// <summary>
/// Initializes a new instance of the <see cref="ModdedToggleOption"/> class.
/// </summary>
@@ -39,7 +44,7 @@ public class ModdedToggleOption : ModdedOption<bool>
toggleOption.Title = StringName;
toggleOption.TitleText.text = Title.Translate();
toggleOption.CheckMark.enabled = Value;
toggleOption.OnValueChanged = (Il2CppSystem.Action<OptionBehaviour>)ValueChanged;
toggleOption.OnValueChanged = (Action<OptionBehaviour>)ValueChanged;
OptionBehaviour = toggleOption;
@@ -76,7 +81,7 @@ public class ModdedToggleOption : ModdedOption<bool>
ModdedOptionsManager.AddSettingsChangeMessage(
HudManager.Instance.Notifier,
StringName,
newValue ? "On" : "Off",
DisplayValue(newValue).Translate(),
Configuration.PopUpTextColor,
Configuration.PopUpIconTmp,
false);
@@ -126,7 +126,7 @@ public sealed class HideAndSeekHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
currentFinalHideTime = totalFinalHideTime;
if (timerBar != null)
{
Object.Destroy(timerBar);
Destroy(timerBar);
}
finalHideAlertSfx = GameManagerCreator.Instance.HideAndSeekManagerPrefab.FinalHideAlertSFX;
+1 -1
View File
@@ -151,7 +151,7 @@ public sealed class MiraHudHelper(nint cppPtr) : MonoBehaviour(cppPtr)
var oldPos = settingsButton.transform.localPosition;
settingsButton.transform.localPosition = new Vector3(oldPos.x, oldPos.y, -100);
var chatButton = instance.Chat.chatButton.gameObject;
ClonedChatButton = Object.Instantiate(chatButton, chatButton.transform.parent);
ClonedChatButton = Instantiate(chatButton, chatButton.transform.parent);
ClonedChatButton.SetActive(false);
instance.Chat.chatButtonAspectPosition = ClonedChatButton.GetComponent<AspectPosition>();
chatButton.GetComponent<AspectPosition>().Destroy();
+8 -7
View File
@@ -313,9 +313,9 @@ public sealed class MiraPluginManager
foreach (var property in type.GetProperties())
{
if (property.GetMethod?.IsStatic == true)
if (property.GetMethod?.IsStatic == true && property.GetCustomAttribute<MiraIgnoreAttribute>() == null)
{
Error($"Option property {property.Name} in {type.Name} must not be static.");
Error($"Non-ignored option property {property.Name} in {type.Name} must not be static.");
continue;
}
@@ -325,6 +325,12 @@ public sealed class MiraPluginManager
continue;
}
if (property.PropertyType.IsAssignableTo(typeof(IModdedOptionList)))
{
ModdedOptionsManager.RegisterPropertyOptionList(type, property, pluginInfo);
continue;
}
var attribute = property.GetCustomAttribute<ModdedOptionAttribute>();
if (attribute != null)
{
@@ -332,11 +338,6 @@ public sealed class MiraPluginManager
continue;
}
if (property.PropertyType.IsAssignableTo(typeof(IModdedOptionList)))
{
ModdedOptionsManager.RegisterPropertyOptionList(type, property, pluginInfo);
}
var listAttr = property.GetCustomAttribute<ModdedOptionListAttribute>();
if (listAttr != null)
{