From a86a73bbf53bec4918ad9a0e0a7d28c2c73dd5c0 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 13 May 2022 15:01:50 +0200 Subject: [PATCH] Make the limit of 32 options for a multi-select group explicit and handle it better. --- Penumbra/Import/TexToolsImporter.ModPack.cs | 73 +++++++++++-------- Penumbra/Mods/Subclasses/IModGroup.cs | 2 + .../Subclasses/Mod.Files.MultiModGroup.cs | 6 ++ Penumbra/Mods/Subclasses/ModSettings.cs | 2 +- Penumbra/UI/ConfigWindow.ModPanel.Edit.cs | 27 +++++-- 5 files changed, 73 insertions(+), 37 deletions(-) diff --git a/Penumbra/Import/TexToolsImporter.ModPack.cs b/Penumbra/Import/TexToolsImporter.ModPack.cs index a6339f5c..0b461860 100644 --- a/Penumbra/Import/TexToolsImporter.ModPack.cs +++ b/Penumbra/Import/TexToolsImporter.ModPack.cs @@ -120,6 +120,7 @@ public partial class TexToolsImporter { groupName = $"{baseName} ({i++})"; } + return groupName; } @@ -160,46 +161,58 @@ public partial class TexToolsImporter { foreach( var group in page.ModGroups.Where( group => group.GroupName.Length > 0 && group.OptionList.Length > 0 ) ) { + var allOptions = group.OptionList.Where( option => option.Name.Length > 0 && option.ModsJsons.Length > 0 ).ToList(); + var (numGroups, maxOptions) = group.SelectionType == SelectType.Single + ? ( 1, allOptions.Count ) + : ( 1 + allOptions.Count / IModGroup.MaxMultiOptions, IModGroup.MaxMultiOptions ); _currentGroupName = GetGroupName( group.GroupName, groupNames ); - options.Clear(); - var description = new StringBuilder(); - var groupFolder = Mod.NewSubFolderName( _currentModDirectory, _currentGroupName ) - ?? new DirectoryInfo( Path.Combine( _currentModDirectory.FullName, $"Group {groupPriority + 1}" ) ); - var optionIdx = 1; - - foreach( var option in group.OptionList.Where( option => option.Name.Length > 0 && option.ModsJsons.Length > 0 ) ) + var optionIdx = 0; + for( var groupId = 0; groupId < numGroups; ++groupId ) { - _token.ThrowIfCancellationRequested(); - _currentOptionName = option.Name; - var optionFolder = Mod.NewSubFolderName( groupFolder, option.Name ) - ?? new DirectoryInfo( Path.Combine( groupFolder.FullName, $"Option {optionIdx}" ) ); - ExtractSimpleModList( optionFolder, option.ModsJsons ); - options.Add( Mod.CreateSubMod( _currentModDirectory, optionFolder, option ) ); - description.Append( option.Description ); - if( !string.IsNullOrEmpty( option.Description ) ) + var name = numGroups == 1 ? _currentGroupName : $"{_currentGroupName}, Part {groupId + 1}"; + options.Clear(); + var description = new StringBuilder(); + var groupFolder = Mod.NewSubFolderName( _currentModDirectory, name ) + ?? new DirectoryInfo( Path.Combine( _currentModDirectory.FullName, + numGroups == 1 ? $"Group {groupPriority + 1}" : $"Group {groupPriority + 1}, Part {groupId + 1}" ) ); + + for( var i = 0; i + optionIdx < allOptions.Count && i < maxOptions; ++i ) { - description.Append( '\n' ); + var option = allOptions[ i + optionIdx ]; + _token.ThrowIfCancellationRequested(); + _currentOptionName = option.Name; + var optionFolder = Mod.NewSubFolderName( groupFolder, option.Name ) + ?? new DirectoryInfo( Path.Combine( groupFolder.FullName, $"Option {i + optionIdx + 1}" ) ); + ExtractSimpleModList( optionFolder, option.ModsJsons ); + options.Add( Mod.CreateSubMod( _currentModDirectory, optionFolder, option ) ); + description.Append( option.Description ); + if( !string.IsNullOrEmpty( option.Description ) ) + { + description.Append( '\n' ); + } + + ++_currentOptionIdx; } - ++optionIdx; - ++_currentOptionIdx; - } + optionIdx += maxOptions; - // Handle empty options for single select groups without creating a folder for them. - // We only want one of those at most, and it should usually be the first option. - if( group.SelectionType == SelectType.Single ) - { - var empty = group.OptionList.FirstOrDefault( o => o.Name.Length > 0 && o.ModsJsons.Length == 0 ); - if( empty != null ) + // Handle empty options for single select groups without creating a folder for them. + // We only want one of those at most, and it should usually be the first option. + if( group.SelectionType == SelectType.Single ) { - _currentOptionName = empty.Name; - options.Insert( 0, Mod.CreateEmptySubMod( empty.Name ) ); + var empty = group.OptionList.FirstOrDefault( o => o.Name.Length > 0 && o.ModsJsons.Length == 0 ); + if( empty != null ) + { + _currentOptionName = empty.Name; + options.Insert( 0, Mod.CreateEmptySubMod( empty.Name ) ); + } } - } - Mod.CreateOptionGroup( _currentModDirectory, group.SelectionType, _currentGroupName, groupPriority, groupPriority, description.ToString(), options ); - ++groupPriority; + Mod.CreateOptionGroup( _currentModDirectory, group.SelectionType, name, groupPriority, groupPriority, + description.ToString(), options ); + ++groupPriority; + } } } diff --git a/Penumbra/Mods/Subclasses/IModGroup.cs b/Penumbra/Mods/Subclasses/IModGroup.cs index 03fc5685..8482af4a 100644 --- a/Penumbra/Mods/Subclasses/IModGroup.cs +++ b/Penumbra/Mods/Subclasses/IModGroup.cs @@ -15,6 +15,8 @@ public enum SelectType public interface IModGroup : IEnumerable< ISubMod > { + public const int MaxMultiOptions = 32; + public string Name { get; } public string Description { get; } public SelectType Type { get; } diff --git a/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs b/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs index 26d3abe3..d84ae760 100644 --- a/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs +++ b/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; +using Dalamud.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using OtterGui.Filesystem; @@ -57,6 +58,11 @@ public partial class Mod { foreach( var child in options.Children() ) { + if( ret.PrioritizedOptions.Count == IModGroup.MaxMultiOptions ) + { + PluginLog.Warning($"Multi Group {ret.Name} has more than {IModGroup.MaxMultiOptions} options, ignoring excessive options." ); + break; + } var subMod = new SubMod(); subMod.Load( basePath, child, out var priority ); ret.PrioritizedOptions.Add( ( subMod, priority ) ); diff --git a/Penumbra/Mods/Subclasses/ModSettings.cs b/Penumbra/Mods/Subclasses/ModSettings.cs index 3f6b7b53..50341ae9 100644 --- a/Penumbra/Mods/Subclasses/ModSettings.cs +++ b/Penumbra/Mods/Subclasses/ModSettings.cs @@ -101,7 +101,7 @@ public class ModSettings => group.Type switch { SelectType.Single => ( uint )Math.Min( value, group.Count - 1 ), - SelectType.Multi => ( uint )( value & ( ( 1 << group.Count ) - 1 ) ), + SelectType.Multi => ( uint )( value & ( ( 1ul << group.Count ) - 1 ) ), _ => value, }; diff --git a/Penumbra/UI/ConfigWindow.ModPanel.Edit.cs b/Penumbra/UI/ConfigWindow.ModPanel.Edit.cs index d2038205..a878e293 100644 --- a/Penumbra/UI/ConfigWindow.ModPanel.Edit.cs +++ b/Penumbra/UI/ConfigWindow.ModPanel.Edit.cs @@ -518,8 +518,13 @@ public partial class ConfigWindow } ImGui.TableNextColumn(); + var canAddGroup = mod.Groups[ groupIdx ].Type != SelectType.Multi || mod.Groups[ groupIdx ].Count < IModGroup.MaxMultiOptions; + var validName = _newOptionName.Length > 0 && _newOptionNameIdx == groupIdx; + var tt = canAddGroup + ? validName ? "Add a new option to this group." : "Please enter a name for the new option." + : $"Can not add more than {IModGroup.MaxMultiOptions} options to a multi group."; if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Plus.ToIconString(), iconButtonSize, - "Add a new option to this group.", _newOptionName.Length == 0 || _newOptionNameIdx != groupIdx, true ) ) + tt, !( canAddGroup && validName ), true ) ) { Penumbra.ModManager.AddOption( mod, groupIdx, _newOptionName ); _newOptionName = string.Empty; @@ -598,12 +603,22 @@ public partial class ConfigWindow return; } - foreach( var type in new[] { SelectType.Single, SelectType.Multi } ) + if( ImGui.Selectable( GroupTypeName( SelectType.Single ), group.Type == SelectType.Single ) ) { - if( ImGui.Selectable( GroupTypeName( type ), @group.Type == type ) ) - { - Penumbra.ModManager.ChangeModGroupType( _mod, groupIdx, type ); - } + Penumbra.ModManager.ChangeModGroupType( _mod, groupIdx, SelectType.Single ); + } + + var canSwitchToMulti = group.Count <= IModGroup.MaxMultiOptions; + using var style = ImRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f, !canSwitchToMulti ); + if( ImGui.Selectable( GroupTypeName( SelectType.Multi ), group.Type == SelectType.Multi ) && canSwitchToMulti ) + { + Penumbra.ModManager.ChangeModGroupType( _mod, groupIdx, SelectType.Multi ); + } + + style.Pop(); + if( !canSwitchToMulti ) + { + ImGuiUtil.HoverTooltip( $"Can not convert group to multi group since it has more than {IModGroup.MaxMultiOptions} options." ); } }