/// <summary> /// Invokes the relevant method(s) specified with <see cref="OnChangeAttribute"/>(s) /// and passes parameters when a value is changed. /// </summary> /// <typeparam name="TSource">The type of the event args.</typeparam> /// <param name="modOptionMetadata">The metadata for the mod option.</param> /// <param name="sender">The sender of the event.</param> /// <param name="e">The event args from the OnChange event.</param> private void InvokeOnChangeEvents <TSource>(ModOptionAttributeMetadata <T> modOptionMetadata, object sender, TSource e) where TSource : IModOptionEventArgs { if (modOptionMetadata.OnChangeMetadata == null) { return; // Skip attempting to invoke events if there are no OnChangeAttributes set for the member. } foreach (MemberInfoMetadata <T> onChangeMetadata in modOptionMetadata.OnChangeMetadata) { InvokeEvent(onChangeMetadata, sender, e); } }
/// <summary> /// Adds options to the menu based on the <see cref="ConfigFileMetadata"/>. /// </summary> public override void BuildModOptions() { // Conditionally load the config if (ConfigFileMetadata.MenuAttribute.LoadOn.HasFlag(MenuAttribute.LoadEvents.MenuOpened)) { ConfigFileMetadata.Config.Load(); } foreach (KeyValuePair <string, ModOptionAttributeMetadata <T> > entry in ConfigFileMetadata.ModOptionAttributesMetadata .OrderBy(x => x.Value.ModOptionAttribute.Order) .ThenBy(x => x.Value.MemberInfoMetadata.Name)) { string id = entry.Key; ModOptionAttributeMetadata <T> modOptionMetadata = entry.Value; string label = modOptionMetadata.ModOptionAttribute.Label; if (Language.main.TryGet(modOptionMetadata.ModOptionAttribute.LabelLanguageId, out string languageLabel)) { label = languageLabel; } Logger.Debug($"[{ConfigFileMetadata.QMod.DisplayName}] [{typeof(T).Name}] {modOptionMetadata.MemberInfoMetadata.Name}: " + $"{modOptionMetadata.ModOptionAttribute.GetType().Name}"); Logger.Debug($"[{ConfigFileMetadata.QMod.DisplayName}] [{typeof(T).Name}] Label: {label}"); switch (modOptionMetadata.ModOptionAttribute) { case ButtonAttribute _: BuildModButtonOption(id, label); break; case ChoiceAttribute choiceAttribute: BuildModChoiceOption(id, label, modOptionMetadata.MemberInfoMetadata, choiceAttribute); break; case KeybindAttribute _: BuildModKeybindOption(id, label, modOptionMetadata.MemberInfoMetadata); break; case SliderAttribute sliderAttribute: BuildModSliderOption(id, label, modOptionMetadata.MemberInfoMetadata, sliderAttribute); break; case ToggleAttribute _: BuildModToggleOption(id, label, modOptionMetadata.MemberInfoMetadata); break; } } }
/// <summary> /// Generates a <see cref="ModOptionAttributeMetadata{T}"/> based on the member and its attributes, then adds it to the /// <see cref="ModOptionAttributesMetadata"/> dictionary. /// </summary> /// <typeparam name="TAttribute">The type of the <see cref="ModOption"/> to generate for this member.</typeparam> /// <param name="memberInfo">The <see cref="MemberInfo"/> of the member.</param> /// <param name="memberType">The <see cref="MemberType"/> of the member.</param> /// <param name="underlyingType">The underlying <see cref="Type"/> of the member.</param> private void addModOptionMetadata <TAttribute>(MemberInfo memberInfo, MemberType memberType, Type underlyingType = null) where TAttribute : ModOptionAttribute, new() { try { // Get the ModOptionAttribute ModOptionAttribute modOptionAttribute = memberInfo.GetCustomAttribute <ModOptionAttribute>(true) ?? new TAttribute(); // If there is no label specified, just use the member's name. if (string.IsNullOrEmpty(modOptionAttribute.Label)) { modOptionAttribute.Label = memberInfo.Name; } // ModOptionMetadata needed for all ModOptions var modOptionMetadata = new ModOptionAttributeMetadata <T> { ModOptionAttribute = modOptionAttribute, MemberInfoMetadata = new MemberInfoMetadata <T> { MemberType = memberType, Name = memberInfo.Name, ValueType = underlyingType }, OnGameObjectCreatedMetadata = GetEventMetadata <OnGameObjectCreatedAttribute>(memberInfo) }; if (memberType == MemberType.Method) { modOptionMetadata.MemberInfoMetadata.ParseMethodParameterTypes(memberInfo as MethodInfo); } if (typeof(TAttribute) != typeof(ButtonAttribute)) { modOptionMetadata.OnChangeMetadata = GetEventMetadata <OnChangeAttribute>(memberInfo); } ModOptionAttributesMetadata.Add(modOptionAttribute.Id, modOptionMetadata); } catch (Exception ex) { Logger.Error($"[OptionsMenuBuilder] {ex.Message}"); } }
/// <summary> /// Invokes the relevant method(s) specified with the <see cref="OnChangeAttribute"/>(s) /// and passes parameters when a value is changed when loaded from disk. /// </summary> /// <param name="modOptionMetadata">The metadata for the mod option.</param> /// <param name="sender">The sender of the event.</param> private void InvokeOnChangeEvents(ModOptionAttributeMetadata <T> modOptionMetadata, object sender) { string id = modOptionMetadata.ModOptionAttribute.Id; MemberInfoMetadata <T> memberInfoMetadata = modOptionMetadata.MemberInfoMetadata; switch (modOptionMetadata.ModOptionAttribute) { case ChoiceAttribute choiceAttribute when memberInfoMetadata.ValueType.IsEnum && (choiceAttribute.Options == null || !choiceAttribute.Options.Any()): // Enum-based choice where the values are parsed from the enum type { string[] options = Enum.GetNames(memberInfoMetadata.ValueType); string value = memberInfoMetadata.GetValue(Config).ToString(); var eventArgs = new ChoiceChangedEventArgs(id, Array.IndexOf(options, value), value); InvokeOnChangeEvents(modOptionMetadata, sender, eventArgs); } break; case ChoiceAttribute _ when memberInfoMetadata.ValueType.IsEnum: // Enum-based choice where the values are defined as custom strings { string value = memberInfoMetadata.GetValue(Config).ToString(); int index = Math.Max(Array.IndexOf(Enum.GetValues(memberInfoMetadata.ValueType), value), 0); var eventArgs = new ChoiceChangedEventArgs(id, index, value); InvokeOnChangeEvents(modOptionMetadata, sender, eventArgs); } break; case ChoiceAttribute choiceAttribute when memberInfoMetadata.ValueType == typeof(string): // string-based choice value { string[] options = choiceAttribute.Options; string value = memberInfoMetadata.GetValue <string>(Config); var eventArgs = new ChoiceChangedEventArgs(id, Array.IndexOf(options, value), value); InvokeOnChangeEvents(modOptionMetadata, sender, eventArgs); } break; case ChoiceAttribute choiceAttribute when memberInfoMetadata.ValueType == typeof(int): // index-based choice value { string[] options = choiceAttribute.Options; int index = memberInfoMetadata.GetValue <int>(Config); var eventArgs = new ChoiceChangedEventArgs(id, index, options[index]); InvokeOnChangeEvents(modOptionMetadata, sender, eventArgs); } break; case KeybindAttribute _: { var eventArgs = new KeybindChangedEventArgs(id, memberInfoMetadata.GetValue <KeyCode>(Config)); InvokeOnChangeEvents(modOptionMetadata, sender, eventArgs); } break; case SliderAttribute _: { var eventArgs = new SliderChangedEventArgs(id, Convert.ToSingle(memberInfoMetadata.GetValue(Config))); InvokeOnChangeEvents(modOptionMetadata, sender, eventArgs); } break; case ToggleAttribute _: { var eventArgs = new ToggleChangedEventArgs(id, memberInfoMetadata.GetValue <bool>(Config)); InvokeOnChangeEvents(modOptionMetadata, sender, eventArgs); } break; } }
private IEnumerator DeferredInvokeOnChangeEventsRoutine(ModOptionAttributeMetadata <T> modOptionMetadata, object sender) { yield return(new WaitUntil(() => Registered)); InvokeOnChangeEvents(modOptionMetadata, sender); }
public bool TryGetMetadata(string id, out ModOptionAttributeMetadata <T> modOptionAttributeMetadata) { return(ModOptionAttributesMetadata.TryGetValue(id, out modOptionAttributeMetadata)); }