/// <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);
     }
 }
Ejemplo n.º 2
0
        /// <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));
 }