diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index 8e609cb7..be3a01ac 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -829,7 +829,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi public PenumbraApiEc CreateNamedTemporaryCollection( string name ) { CheckInitialized(); - if( name.Length == 0 || Mod.ReplaceBadXivSymbols( name ) != name ) + if( name.Length == 0 || Mod.Creator.ReplaceBadXivSymbols( name ) != name ) { return PenumbraApiEc.InvalidArgument; } diff --git a/Penumbra/Import/TexToolsImporter.Archives.cs b/Penumbra/Import/TexToolsImporter.Archives.cs index a6403027..a00d042c 100644 --- a/Penumbra/Import/TexToolsImporter.Archives.cs +++ b/Penumbra/Import/TexToolsImporter.Archives.cs @@ -44,7 +44,7 @@ public partial class TexToolsImporter }; Penumbra.Log.Information( $" -> Importing {archive.Type} Archive." ); - _currentModDirectory = Mod.CreateModFolder( _baseDirectory, Path.GetRandomFileName() ); + _currentModDirectory = Mod.Creator.CreateModFolder( _baseDirectory, Path.GetRandomFileName() ); var options = new ExtractionOptions() { ExtractFullPath = true, @@ -99,13 +99,13 @@ public partial class TexToolsImporter // Use either the top-level directory as the mods base name, or the (fixed for path) name in the json. if( leadDir ) { - _currentModDirectory = Mod.CreateModFolder( _baseDirectory, baseName, false ); + _currentModDirectory = Mod.Creator.CreateModFolder( _baseDirectory, baseName, false ); Directory.Move( Path.Combine( oldName, baseName ), _currentModDirectory.FullName ); Directory.Delete( oldName ); } else { - _currentModDirectory = Mod.CreateModFolder( _baseDirectory, name, false ); + _currentModDirectory = Mod.Creator.CreateModFolder( _baseDirectory, name, false ); Directory.Move( oldName, _currentModDirectory.FullName ); } @@ -114,6 +114,7 @@ public partial class TexToolsImporter return _currentModDirectory; } + // Search the archive for the meta.json file which needs to exist. private static string FindArchiveModMeta( IArchive archive, out bool leadDir ) { diff --git a/Penumbra/Import/TexToolsImporter.ModPack.cs b/Penumbra/Import/TexToolsImporter.ModPack.cs index e2edfe92..2fb79390 100644 --- a/Penumbra/Import/TexToolsImporter.ModPack.cs +++ b/Penumbra/Import/TexToolsImporter.ModPack.cs @@ -34,14 +34,14 @@ public partial class TexToolsImporter var modList = modListRaw.Select( m => JsonConvert.DeserializeObject< SimpleMod >( m, JsonSettings )! ).ToList(); - _currentModDirectory = Mod.CreateModFolder( _baseDirectory, Path.GetFileNameWithoutExtension( modPackFile.Name ) ); + _currentModDirectory = Mod.Creator.CreateModFolder( _baseDirectory, Path.GetFileNameWithoutExtension( modPackFile.Name ) ); // Create a new ModMeta from the TTMP mod list info - Mod.CreateMeta( _currentModDirectory, _currentModName, DefaultTexToolsData.Author, DefaultTexToolsData.Description, null, null ); + Mod.Creator.CreateMeta( _currentModDirectory, _currentModName, DefaultTexToolsData.Author, DefaultTexToolsData.Description, null, null ); // Open the mod data file from the mod pack as a SqPackStream _streamDisposer = GetSqPackStreamStream( extractedModPack, "TTMPD.mpd" ); ExtractSimpleModList( _currentModDirectory, modList ); - Mod.CreateDefaultFiles( _currentModDirectory ); + Mod.Creator.CreateDefaultFiles( _currentModDirectory ); ResetStreamDisposer(); return _currentModDirectory; } @@ -90,15 +90,15 @@ public partial class TexToolsImporter _currentOptionName = DefaultTexToolsData.DefaultOption; Penumbra.Log.Information( " -> Importing Simple V2 ModPack" ); - _currentModDirectory = Mod.CreateModFolder( _baseDirectory, _currentModName ); - Mod.CreateMeta( _currentModDirectory, _currentModName, modList.Author, string.IsNullOrEmpty( modList.Description ) + _currentModDirectory = Mod.Creator.CreateModFolder( _baseDirectory, _currentModName ); + Mod.Creator.CreateMeta( _currentModDirectory, _currentModName, modList.Author, string.IsNullOrEmpty( modList.Description ) ? "Mod imported from TexTools mod pack" : modList.Description, modList.Version, modList.Url ); // Open the mod data file from the mod pack as a SqPackStream _streamDisposer = GetSqPackStreamStream( extractedModPack, "TTMPD.mpd" ); ExtractSimpleModList( _currentModDirectory, modList.SimpleModsList ); - Mod.CreateDefaultFiles( _currentModDirectory ); + Mod.Creator.CreateDefaultFiles( _currentModDirectory ); ResetStreamDisposer(); return _currentModDirectory; } @@ -135,8 +135,8 @@ public partial class TexToolsImporter _currentNumOptions = GetOptionCount( modList ); _currentModName = modList.Name; - _currentModDirectory = Mod.CreateModFolder( _baseDirectory, _currentModName ); - Mod.CreateMeta( _currentModDirectory, _currentModName, modList.Author, modList.Description, modList.Version, modList.Url ); + _currentModDirectory = Mod.Creator.CreateModFolder( _baseDirectory, _currentModName ); + Mod.Creator.CreateMeta( _currentModDirectory, _currentModName, modList.Author, modList.Description, modList.Version, modList.Url ); if( _currentNumOptions == 0 ) { @@ -173,7 +173,7 @@ public partial class TexToolsImporter { var name = numGroups == 1 ? _currentGroupName : $"{_currentGroupName}, Part {groupId + 1}"; options.Clear(); - var groupFolder = Mod.NewSubFolderName( _currentModDirectory, name ) + var groupFolder = Mod.Creator.NewSubFolderName( _currentModDirectory, name ) ?? new DirectoryInfo( Path.Combine( _currentModDirectory.FullName, numGroups == 1 ? $"Group {groupPriority + 1}" : $"Group {groupPriority + 1}, Part {groupId + 1}" ) ); @@ -183,10 +183,10 @@ public partial class TexToolsImporter var option = allOptions[ i + optionIdx ]; _token.ThrowIfCancellationRequested(); _currentOptionName = option.Name; - var optionFolder = Mod.NewSubFolderName( groupFolder, option.Name ) + var optionFolder = Mod.Creator.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 ) ); + options.Add( Mod.Creator.CreateSubMod( _currentModDirectory, optionFolder, option ) ); if( option.IsChecked ) { defaultSettings = group.SelectionType == GroupType.Multi @@ -207,12 +207,12 @@ public partial class TexToolsImporter if( empty != null ) { _currentOptionName = empty.Name; - options.Insert( 0, Mod.CreateEmptySubMod( empty.Name ) ); + options.Insert( 0, Mod.Creator.CreateEmptySubMod( empty.Name ) ); defaultSettings = defaultSettings == null ? 0 : defaultSettings.Value + 1; } } - Mod.CreateOptionGroup( _currentModDirectory, group.SelectionType, name, groupPriority, groupPriority, + Mod.Creator.CreateOptionGroup( _currentModDirectory, group.SelectionType, name, groupPriority, groupPriority, defaultSettings ?? 0, group.Description, options ); ++groupPriority; } @@ -220,7 +220,7 @@ public partial class TexToolsImporter } ResetStreamDisposer(); - Mod.CreateDefaultFiles( _currentModDirectory ); + Mod.Creator.CreateDefaultFiles( _currentModDirectory ); return _currentModDirectory; } diff --git a/Penumbra/Mods/Editor/Mod.Normalization.cs b/Penumbra/Mods/Editor/Mod.Normalization.cs index 73a92a09..0696271d 100644 --- a/Penumbra/Mods/Editor/Mod.Normalization.cs +++ b/Penumbra/Mods/Editor/Mod.Normalization.cs @@ -150,11 +150,11 @@ public partial class Mod foreach( var (group, groupIdx) in _mod.Groups.WithIndex() ) { _redirections[ groupIdx + 1 ] = new Dictionary< Utf8GamePath, FullPath >[group.Count]; - var groupDir = CreateModFolder( directory, group.Name ); + var groupDir = Creator.CreateModFolder( directory, group.Name ); foreach( var option in group.OfType< SubMod >() ) { - var optionDir = CreateModFolder( groupDir, option.Name ); + var optionDir = Creator.CreateModFolder( groupDir, option.Name ); newDict = new Dictionary< Utf8GamePath, FullPath >( option.FileData.Count ); _redirections[ groupIdx + 1 ][ option.OptionIdx ] = newDict; foreach( var (gamePath, fullPath) in option.FileData ) diff --git a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs index a1de7b7a..51b3dea0 100644 --- a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs +++ b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs @@ -64,12 +64,6 @@ public static class EquipmentSwap var imcFileTo = new ImcFile( imcManip); var isAccessory = slot.IsAccessory(); - var estType = slot switch - { - EquipSlot.Head => EstManipulation.EstType.Head, - EquipSlot.Body => EstManipulation.EstType.Body, - _ => ( EstManipulation.EstType )0, - }; var skipFemale = false; var skipMale = false; @@ -89,12 +83,6 @@ public static class EquipmentSwap continue; } - var est = ItemSwap.CreateEst( redirections, manips, estType, gr, idFrom, idTo ); - if( est != null ) - { - swaps.Add( est ); - } - try { var eqdp = CreateEqdp( redirections, manips, slot, gr, idFrom, idTo, mtrlVariantTo ); @@ -140,6 +128,19 @@ public static class EquipmentSwap { var mdl = CreateMdl( redirections, slot, gr, idFrom, idTo, mtrlTo ); meta.ChildSwaps.Add( mdl ); + + var estType = slot switch + { + EquipSlot.Head => EstManipulation.EstType.Head, + EquipSlot.Body => EstManipulation.EstType.Body, + _ => ( EstManipulation.EstType )0, + }; + + var est = ItemSwap.CreateEst( redirections, manips, estType, gr, idFrom, idTo ); + if( est != null ) + { + meta.ChildSwaps.Add( est ); + } } else if( !ownMtrl && meta.SwapAppliedIsDefault ) { diff --git a/Penumbra/Mods/Manager/Mod.Manager.BasePath.cs b/Penumbra/Mods/Manager/Mod.Manager.BasePath.cs index 8f092ed4..3712831f 100644 --- a/Penumbra/Mods/Manager/Mod.Manager.BasePath.cs +++ b/Penumbra/Mods/Manager/Mod.Manager.BasePath.cs @@ -175,7 +175,7 @@ public partial class Mod return NewDirectoryState.Identical; } - var fixedNewName = ReplaceBadXivSymbols( newName ); + var fixedNewName = Creator.ReplaceBadXivSymbols( newName ); if( fixedNewName != newName ) { return NewDirectoryState.ContainsInvalidSymbols; diff --git a/Penumbra/Mods/Mod.Creation.cs b/Penumbra/Mods/Mod.Creation.cs deleted file mode 100644 index 13cd4ab7..00000000 --- a/Penumbra/Mods/Mod.Creation.cs +++ /dev/null @@ -1,187 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using Dalamud.Utility; -using OtterGui.Classes; -using OtterGui.Filesystem; -using Penumbra.Api.Enums; -using Penumbra.Import; -using Penumbra.String.Classes; - -namespace Penumbra.Mods; - -public partial class Mod -{ - /// - /// Create and return a new directory based on the given directory and name, that is
- /// - Not Empty.
- /// - Unique, by appending (digit) for duplicates.
- /// - Containing no symbols invalid for FFXIV or windows paths.
- ///
- /// - /// - /// - /// - /// - internal static DirectoryInfo CreateModFolder( DirectoryInfo outDirectory, string modListName, bool create = true ) - { - var name = modListName; - if( name.Length == 0 ) - { - name = "_"; - } - - var newModFolderBase = NewOptionDirectory( outDirectory, name ); - var newModFolder = newModFolderBase.FullName.ObtainUniqueFile(); - if( newModFolder.Length == 0 ) - { - throw new IOException( "Could not create mod folder: too many folders of the same name exist." ); - } - - if( create ) - { - Directory.CreateDirectory( newModFolder ); - } - - return new DirectoryInfo( newModFolder ); - } - - /// - /// Create the name for a group or option subfolder based on its parent folder and given name. - /// subFolderName should never be empty, and the result is unique and contains no invalid symbols. - /// - internal static DirectoryInfo? NewSubFolderName( DirectoryInfo parentFolder, string subFolderName ) - { - var newModFolderBase = NewOptionDirectory( parentFolder, subFolderName ); - var newModFolder = newModFolderBase.FullName.ObtainUniqueFile(); - return newModFolder.Length == 0 ? null : new DirectoryInfo( newModFolder ); - } - - // Create the file containing the meta information about a mod from scratch. - internal static void CreateMeta( DirectoryInfo directory, string? name, string? author, string? description, string? version, - string? website ) - { - var mod = new Mod( directory ); - mod.Name = name.IsNullOrEmpty() ? mod.Name : new LowerString( name! ); - mod.Author = author != null ? new LowerString( author ) : mod.Author; - mod.Description = description ?? mod.Description; - mod.Version = version ?? mod.Version; - mod.Website = website ?? mod.Website; - mod.SaveMetaFile(); // Not delayed. - } - - // Create a file for an option group from given data. - internal static void CreateOptionGroup( DirectoryInfo baseFolder, GroupType type, string name, - int priority, int index, uint defaultSettings, string desc, IEnumerable< ISubMod > subMods ) - { - switch( type ) - { - case GroupType.Multi: - { - var group = new MultiModGroup() - { - Name = name, - Description = desc, - Priority = priority, - DefaultSettings = defaultSettings, - }; - group.PrioritizedOptions.AddRange( subMods.OfType< SubMod >().Select( ( s, idx ) => ( s, idx ) ) ); - IModGroup.Save( group, baseFolder, index ); - break; - } - case GroupType.Single: - { - var group = new SingleModGroup() - { - Name = name, - Description = desc, - Priority = priority, - DefaultSettings = defaultSettings, - }; - group.OptionData.AddRange( subMods.OfType< SubMod >() ); - IModGroup.Save( group, baseFolder, index ); - break; - } - } - } - - // Create the data for a given sub mod from its data and the folder it is based on. - internal static ISubMod CreateSubMod( DirectoryInfo baseFolder, DirectoryInfo optionFolder, OptionList option ) - { - var list = optionFolder.EnumerateFiles( "*.*", SearchOption.AllDirectories ) - .Select( f => ( Utf8GamePath.FromFile( f, optionFolder, out var gamePath, true ), gamePath, new FullPath( f ) ) ) - .Where( t => t.Item1 ); - - var mod = new SubMod( null! ) // Mod is irrelevant here, only used for saving. - { - Name = option.Name, - Description = option.Description, - }; - foreach( var (_, gamePath, file) in list ) - { - mod.FileData.TryAdd( gamePath, file ); - } - - mod.IncorporateMetaChanges( baseFolder, true ); - return mod; - } - - // Create an empty sub mod for single groups with None options. - internal static ISubMod CreateEmptySubMod( string name ) - => new SubMod( null! ) // Mod is irrelevant here, only used for saving. - { - Name = name, - }; - - // Create the default data file from all unused files that were not handled before - // and are used in sub mods. - internal static void CreateDefaultFiles( DirectoryInfo directory ) - { - var mod = new Mod( directory ); - mod.Reload( false, out _ ); - foreach( var file in mod.FindUnusedFiles() ) - { - if( Utf8GamePath.FromFile( new FileInfo( file.FullName ), directory, out var gamePath, true ) ) - { - mod._default.FileData.TryAdd( gamePath, file ); - } - } - - mod._default.IncorporateMetaChanges( directory, true ); - mod.SaveDefaultMod(); - } - - // Return the name of a new valid directory based on the base directory and the given name. - private static DirectoryInfo NewOptionDirectory( DirectoryInfo baseDir, string optionName ) - => new(Path.Combine( baseDir.FullName, ReplaceBadXivSymbols( optionName ) )); - - // Normalize for nicer names, and remove invalid symbols or invalid paths. - public static string ReplaceBadXivSymbols( string s, string replacement = "_" ) - { - if( s == "." ) - { - return replacement; - } - - if( s == ".." ) - { - return replacement + replacement; - } - - StringBuilder sb = new(s.Length); - foreach( var c in s.Normalize( NormalizationForm.FormKC ) ) - { - if( c.IsInvalidInPath() ) - { - sb.Append( replacement ); - } - else - { - sb.Append( c ); - } - } - - return sb.ToString(); - } -} \ No newline at end of file diff --git a/Penumbra/Mods/Mod.Creator.cs b/Penumbra/Mods/Mod.Creator.cs new file mode 100644 index 00000000..85fbfa50 --- /dev/null +++ b/Penumbra/Mods/Mod.Creator.cs @@ -0,0 +1,188 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Dalamud.Utility; +using OtterGui.Classes; +using OtterGui.Filesystem; +using Penumbra.Api.Enums; +using Penumbra.Import; +using Penumbra.String.Classes; + +namespace Penumbra.Mods; + +public partial class Mod +{ + internal static class Creator + { + /// + /// Create and return a new directory based on the given directory and name, that is
+ /// - Not Empty.
+ /// - Unique, by appending (digit) for duplicates.
+ /// - Containing no symbols invalid for FFXIV or windows paths.
+ ///
+ /// + /// + /// + /// + /// + public static DirectoryInfo CreateModFolder( DirectoryInfo outDirectory, string modListName, bool create = true ) + { + var name = modListName; + if( name.Length == 0 ) + { + name = "_"; + } + + var newModFolderBase = NewOptionDirectory( outDirectory, name ); + var newModFolder = newModFolderBase.FullName.ObtainUniqueFile(); + if( newModFolder.Length == 0 ) + { + throw new IOException( "Could not create mod folder: too many folders of the same name exist." ); + } + + if( create ) + { + Directory.CreateDirectory( newModFolder ); + } + + return new DirectoryInfo( newModFolder ); + } + + /// + /// Create the name for a group or option subfolder based on its parent folder and given name. + /// subFolderName should never be empty, and the result is unique and contains no invalid symbols. + /// + public static DirectoryInfo? NewSubFolderName( DirectoryInfo parentFolder, string subFolderName ) + { + var newModFolderBase = NewOptionDirectory( parentFolder, subFolderName ); + var newModFolder = newModFolderBase.FullName.ObtainUniqueFile(); + return newModFolder.Length == 0 ? null : new DirectoryInfo( newModFolder ); + } + + /// Create the file containing the meta information about a mod from scratch. + public static void CreateMeta( DirectoryInfo directory, string? name, string? author, string? description, string? version, + string? website ) + { + var mod = new Mod( directory ); + mod.Name = name.IsNullOrEmpty() ? mod.Name : new LowerString( name! ); + mod.Author = author != null ? new LowerString( author ) : mod.Author; + mod.Description = description ?? mod.Description; + mod.Version = version ?? mod.Version; + mod.Website = website ?? mod.Website; + mod.SaveMetaFile(); // Not delayed. + } + + /// Create a file for an option group from given data. + public static void CreateOptionGroup( DirectoryInfo baseFolder, GroupType type, string name, + int priority, int index, uint defaultSettings, string desc, IEnumerable< ISubMod > subMods ) + { + switch( type ) + { + case GroupType.Multi: + { + var group = new MultiModGroup() + { + Name = name, + Description = desc, + Priority = priority, + DefaultSettings = defaultSettings, + }; + group.PrioritizedOptions.AddRange( subMods.OfType< SubMod >().Select( ( s, idx ) => ( s, idx ) ) ); + IModGroup.Save( group, baseFolder, index ); + break; + } + case GroupType.Single: + { + var group = new SingleModGroup() + { + Name = name, + Description = desc, + Priority = priority, + DefaultSettings = defaultSettings, + }; + group.OptionData.AddRange( subMods.OfType< SubMod >() ); + IModGroup.Save( group, baseFolder, index ); + break; + } + } + } + + /// Create the data for a given sub mod from its data and the folder it is based on. + public static ISubMod CreateSubMod( DirectoryInfo baseFolder, DirectoryInfo optionFolder, OptionList option ) + { + var list = optionFolder.EnumerateFiles( "*.*", SearchOption.AllDirectories ) + .Select( f => ( Utf8GamePath.FromFile( f, optionFolder, out var gamePath, true ), gamePath, new FullPath( f ) ) ) + .Where( t => t.Item1 ); + + var mod = new SubMod( null! ) // Mod is irrelevant here, only used for saving. + { + Name = option.Name, + Description = option.Description, + }; + foreach( var (_, gamePath, file) in list ) + { + mod.FileData.TryAdd( gamePath, file ); + } + + mod.IncorporateMetaChanges( baseFolder, true ); + return mod; + } + + /// Create an empty sub mod for single groups with None options. + internal static ISubMod CreateEmptySubMod( string name ) + => new SubMod( null! ) // Mod is irrelevant here, only used for saving. + { + Name = name, + }; + + /// + /// Create the default data file from all unused files that were not handled before + /// and are used in sub mods. + /// + internal static void CreateDefaultFiles( DirectoryInfo directory ) + { + var mod = new Mod( directory ); + mod.Reload( false, out _ ); + foreach( var file in mod.FindUnusedFiles() ) + { + if( Utf8GamePath.FromFile( new FileInfo( file.FullName ), directory, out var gamePath, true ) ) + { + mod._default.FileData.TryAdd( gamePath, file ); + } + } + + mod._default.IncorporateMetaChanges( directory, true ); + mod.SaveDefaultMod(); + } + + /// Return the name of a new valid directory based on the base directory and the given name. + public static DirectoryInfo NewOptionDirectory( DirectoryInfo baseDir, string optionName ) + => new(Path.Combine( baseDir.FullName, ReplaceBadXivSymbols( optionName ) )); + + /// Normalize for nicer names, and remove invalid symbols or invalid paths. + public static string ReplaceBadXivSymbols( string s, string replacement = "_" ) + { + switch( s ) + { + case ".": return replacement; + case "..": return replacement + replacement; + } + + StringBuilder sb = new(s.Length); + foreach( var c in s.Normalize( NormalizationForm.FormKC ) ) + { + if( c.IsInvalidInPath() ) + { + sb.Append( replacement ); + } + else + { + sb.Append( c ); + } + } + + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/Penumbra/Mods/Mod.TemporaryMod.cs b/Penumbra/Mods/Mod.TemporaryMod.cs index 802852e9..6de0a682 100644 --- a/Penumbra/Mods/Mod.TemporaryMod.cs +++ b/Penumbra/Mods/Mod.TemporaryMod.cs @@ -51,9 +51,9 @@ public sealed partial class Mod DirectoryInfo? dir = null; try { - dir = CreateModFolder( Penumbra.ModManager.BasePath, collection.Name ); + dir = Creator.CreateModFolder( Penumbra.ModManager.BasePath, collection.Name ); var fileDir = Directory.CreateDirectory( Path.Combine( dir.FullName, "files" ) ); - CreateMeta( dir, collection.Name, character ?? Penumbra.Config.DefaultModAuthor, + Creator.CreateMeta( dir, collection.Name, character ?? Penumbra.Config.DefaultModAuthor, $"Mod generated from temporary collection {collection.Name} for {character ?? "Unknown Character"}.", null, null ); var mod = new Mod( dir ); var defaultMod = mod._default; diff --git a/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs b/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs index fe7b1173..6b6259f6 100644 --- a/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs +++ b/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs @@ -3,11 +3,13 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using System.Numerics; +using Dalamud.Interface.Internal.Notifications; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using OtterGui; using OtterGui.Filesystem; using Penumbra.Api.Enums; +using Penumbra.Util; namespace Penumbra.Mods; @@ -63,8 +65,7 @@ public partial class Mod { if( ret.PrioritizedOptions.Count == IModGroup.MaxMultiOptions ) { - Penumbra.Log.Warning( - $"Multi Group {ret.Name} has more than {IModGroup.MaxMultiOptions} options, ignoring excessive options." ); + ChatUtil.NotificationMessage( $"Multi Group {ret.Name} has more than {IModGroup.MaxMultiOptions} options, ignoring excessive options.", "Warning", NotificationType.Warning ); break; } diff --git a/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs b/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs index ed0fd1fb..981b336b 100644 --- a/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs +++ b/Penumbra/Mods/Subclasses/Mod.Files.SubMod.cs @@ -67,7 +67,7 @@ public partial class Mod _default.WriteTexToolsMeta( ModPath ); foreach( var group in Groups ) { - var dir = NewOptionDirectory( ModPath, group.Name ); + var dir = Creator.NewOptionDirectory( ModPath, group.Name ); if( !dir.Exists ) { dir.Create(); @@ -75,7 +75,7 @@ public partial class Mod foreach( var option in group.OfType< SubMod >() ) { - var optionDir = NewOptionDirectory( dir, option.Name ); + var optionDir = Creator.NewOptionDirectory( dir, option.Name ); if( !optionDir.Exists ) { optionDir.Create(); diff --git a/Penumbra/UI/Classes/ItemSwapWindow.cs b/Penumbra/UI/Classes/ItemSwapWindow.cs index 8215bcc7..cd551088 100644 --- a/Penumbra/UI/Classes/ItemSwapWindow.cs +++ b/Penumbra/UI/Classes/ItemSwapWindow.cs @@ -216,9 +216,9 @@ public class ItemSwapWindow : IDisposable private void CreateMod() { - var newDir = Mod.CreateModFolder( Penumbra.ModManager.BasePath, _newModName ); - Mod.CreateMeta( newDir, _newModName, Penumbra.Config.DefaultModAuthor, CreateDescription(), "1.0", string.Empty ); - Mod.CreateDefaultFiles( newDir ); + var newDir = Mod.Creator.CreateModFolder( Penumbra.ModManager.BasePath, _newModName ); + Mod.Creator.CreateMeta( newDir, _newModName, Penumbra.Config.DefaultModAuthor, CreateDescription(), "1.0", string.Empty ); + Mod.Creator.CreateDefaultFiles( newDir ); Penumbra.ModManager.AddMod( newDir ); if( !_swapData.WriteMod( Penumbra.ModManager.Last(), _useFileSwaps ? ItemSwapContainer.WriteType.UseSwaps : ItemSwapContainer.WriteType.NoSwaps ) ) { @@ -239,7 +239,7 @@ public class ItemSwapWindow : IDisposable DirectoryInfo? optionFolderName = null; try { - optionFolderName = Mod.NewSubFolderName( new DirectoryInfo( Path.Combine( _mod.ModPath.FullName, _selectedGroup?.Name ?? _newGroupName ) ), _newOptionName ); + optionFolderName = Mod.Creator.NewSubFolderName( new DirectoryInfo( Path.Combine( _mod.ModPath.FullName, _selectedGroup?.Name ?? _newGroupName ) ), _newOptionName ); if( optionFolderName?.Exists == true ) { throw new Exception( $"The folder {optionFolderName.FullName} for the option already exists." ); diff --git a/Penumbra/UI/Classes/ModFileSystemSelector.cs b/Penumbra/UI/Classes/ModFileSystemSelector.cs index 61b46a36..497a2f0e 100644 --- a/Penumbra/UI/Classes/ModFileSystemSelector.cs +++ b/Penumbra/UI/Classes/ModFileSystemSelector.cs @@ -92,9 +92,9 @@ public sealed partial class ModFileSystemSelector : FileSystemSelector< Mod, Mod { try { - var newDir = Mod.CreateModFolder( Penumbra.ModManager.BasePath, _newModName ); - Mod.CreateMeta( newDir, _newModName, Penumbra.Config.DefaultModAuthor, string.Empty, "1.0", string.Empty ); - Mod.CreateDefaultFiles( newDir ); + var newDir = Mod.Creator.CreateModFolder( Penumbra.ModManager.BasePath, _newModName ); + Mod.Creator.CreateMeta( newDir, _newModName, Penumbra.Config.DefaultModAuthor, string.Empty, "1.0", string.Empty ); + Mod.Creator.CreateDefaultFiles( newDir ); Penumbra.ModManager.AddMod( newDir ); _newModName = string.Empty; }