mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-19 15:51:48 +00:00
more stuff
This commit is contained in:
23 files changed
+283
-124
No files matched your search
@@ -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.");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user