From c8edd87df89d39ea73c80fb8ddcf1cffa3f33c12 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 19 Nov 2022 21:16:38 +0100 Subject: [PATCH] Add changelog, improve Support Info, fix bug with folder checking, remove obsolete ownership settings. --- .../Collections/CollectionManager.Active.cs | 2 +- Penumbra/Configuration.cs | 2 - Penumbra/Penumbra.cs | 114 +++++++++--------- Penumbra/UI/ConfigWindow.Changelog.cs | 28 +++++ .../UI/ConfigWindow.SettingsTab.General.cs | 18 +-- Penumbra/UI/ConfigWindow.SettingsTab.cs | 5 + 6 files changed, 99 insertions(+), 70 deletions(-) diff --git a/Penumbra/Collections/CollectionManager.Active.cs b/Penumbra/Collections/CollectionManager.Active.cs index a8feb7f0..355c9297 100644 --- a/Penumbra/Collections/CollectionManager.Active.cs +++ b/Penumbra/Collections/CollectionManager.Active.cs @@ -170,7 +170,7 @@ public partial class ModCollection } // Wrappers around Individual Collection handling. - public void CreateIndividualCollection( ActorIdentifier[] identifiers ) + public void CreateIndividualCollection( params ActorIdentifier[] identifiers ) { if( Individuals.Add( identifiers, Default ) ) { diff --git a/Penumbra/Configuration.cs b/Penumbra/Configuration.cs index 711164dd..b51251a1 100644 --- a/Penumbra/Configuration.cs +++ b/Penumbra/Configuration.cs @@ -37,8 +37,6 @@ public partial class Configuration : IPluginConfiguration public bool UseCharacterCollectionInInspect { get; set; } = true; public bool UseCharacterCollectionInTryOn { get; set; } = true; public bool UseOwnerNameForCharacterCollection { get; set; } = true; - public bool PreferNamedCollectionsOverOwners { get; set; } = true; - public bool UseDefaultCollectionForRetainers { get; set; } = false; public bool HideRedrawBar { get; set; } = false; diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index b7f45c4b..eb04510a 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -28,6 +28,7 @@ using Penumbra.GameData.Actors; using Penumbra.Interop.Loader; using Penumbra.Interop.Resolver; using Penumbra.Mods; +using Penumbra.String; using CharacterUtility = Penumbra.Interop.CharacterUtility; using ResidentResourceManager = Penumbra.Interop.ResidentResourceManager; @@ -337,7 +338,7 @@ public class Penumbra : IDalamudPlugin var split = collectionName.Split( '|', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries ); if( split.Length < 2 || split[ 0 ].Length == 0 || split[ 1 ].Length == 0 ) { - Dalamud.Chat.Print( "You need to provide a collection and a character name in the form of 'collection | character' to set a character collection." ); + Dalamud.Chat.Print( "You need to provide a collection and a character name in the form of 'collection | name' to set an individual collection." ); return false; } @@ -355,27 +356,33 @@ public class Penumbra : IDalamudPlugin return false; } - // TODO - //var oldCollection = CollectionManager.ByType( type, characterName ); - //if( collection == oldCollection ) - //{ - // Dalamud.Chat.Print( $"{collection.Name} already is the {type.ToName()} Collection." ); - // return false; - //} - // - //if( oldCollection == null ) - //{ - // if( type.IsSpecial() ) - // { - // CollectionManager.CreateSpecialCollection( type ); - // } - // else if( type is CollectionType.Individual ) - // { - // CollectionManager.CreateIndividualCollection( characterName! ); - // } - //} - // - //CollectionManager.SetCollection( collection, type, characterName ); + var identifier = Actors.CreatePlayer( ByteString.FromStringUnsafe( characterName, false ), ushort.MaxValue ); + if( !identifier.IsValid ) + { + Dalamud.Chat.Print( $"{characterName} is not a valid character name." ); + return false; + } + + var oldCollection = CollectionManager.ByType( type, identifier ); + if( collection == oldCollection ) + { + Dalamud.Chat.Print( $"{collection.Name} already is the {type.ToName()} Collection." ); + return false; + } + + if( oldCollection == null ) + { + if( type.IsSpecial() ) + { + CollectionManager.CreateSpecialCollection( type ); + } + else if( type is CollectionType.Individual ) + { + CollectionManager.CreateIndividualCollection( identifier ); + } + } + + CollectionManager.SetCollection( collection, type, CollectionManager.Individuals.Count - 1 ); Dalamud.Chat.Print( $"Set {collection.Name} as {type.ToName()} Collection{( characterName != null ? $" for {characterName}." : "." )}" ); return true; } @@ -490,62 +497,61 @@ public class Penumbra : IDalamudPlugin var exists = Config.ModDirectory.Length > 0 && Directory.Exists( Config.ModDirectory ); var drive = exists ? new DriveInfo( new DirectoryInfo( Config.ModDirectory ).Root.FullName ) : null; sb.AppendLine( "**Settings**" ); - sb.AppendFormat( "> **`Plugin Version: `** {0}\n", Version ); - sb.AppendFormat( "> **`Commit Hash: `** {0}\n", CommitHash ); - sb.AppendFormat( "> **`Enable Mods: `** {0}\n", Config.EnableMods ); - sb.AppendFormat( "> **`Enable HTTP API: `** {0}\n", Config.EnableHttpApi ); - sb.AppendFormat( "> **`Root Directory: `** `{0}`, {1}\n", Config.ModDirectory, exists ? "Exists" : "Not Existing" ); - sb.AppendFormat( "> **`Free Drive Space: `** {0}\n", - drive != null ? Functions.HumanReadableSize( drive.AvailableFreeSpace ) : "Unknown" ); + sb.Append( $"> **`Plugin Version: `** {Version}\n" ); + sb.Append( $"> **`Commit Hash: `** {CommitHash}\n" ); + sb.Append( $"> **`Enable Mods: `** {Config.EnableMods}\n" ); + sb.Append( $"> **`Enable HTTP API: `** {Config.EnableHttpApi}\n" ); + sb.Append( $"> **`Root Directory: `** `{Config.ModDirectory}`, {( exists ? "Exists" : "Not Existing" )}\n" ); + sb.Append( $"> **`Free Drive Space: `** {( drive != null ? Functions.HumanReadableSize( drive.AvailableFreeSpace ) : "Unknown" )}\n" ); + sb.Append( $"> **`Auto-Deduplication: `** {Config.AutoDeduplicateOnImport}\n" ); + sb.Append( $"> **`Debug Mode: `** {Config.DebugMode}\n" ); + sb.Append( $"> **`Logging: `** Full: {Config.EnableFullResourceLogging}, Resource: {Config.EnableResourceLogging}\n" ); + sb.Append( $"> **`Use Ownership: `** {Config.UseOwnerNameForCharacterCollection}\n" ); sb.AppendLine( "**Mods**" ); - sb.AppendFormat( "> **`Installed Mods: `** {0}\n", ModManager.Count ); - sb.AppendFormat( "> **`Mods with Config: `** {0}\n", ModManager.Count( m => m.HasOptions ) ); - sb.AppendFormat( "> **`Mods with File Redirections: `** {0}, Total: {1}\n", ModManager.Count( m => m.TotalFileCount > 0 ), - ModManager.Sum( m => m.TotalFileCount ) ); - sb.AppendFormat( "> **`Mods with FileSwaps: `** {0}, Total: {1}\n", ModManager.Count( m => m.TotalSwapCount > 0 ), - ModManager.Sum( m => m.TotalSwapCount ) ); - sb.AppendFormat( "> **`Mods with Meta Manipulations:`** {0}, Total {1}\n", ModManager.Count( m => m.TotalManipulations > 0 ), - ModManager.Sum( m => m.TotalManipulations ) ); - sb.AppendFormat( "> **`IMC Exceptions Thrown: `** {0}\n", ImcExceptions ); + sb.Append( $"> **`Installed Mods: `** {ModManager.Count}\n" ); + sb.Append( $"> **`Mods with Config: `** {ModManager.Count( m => m.HasOptions )}\n" ); + sb.Append( $"> **`Mods with File Redirections: `** {ModManager.Count( m => m.TotalFileCount > 0 )}, Total: {ModManager.Sum( m => m.TotalFileCount )}\n" ); + sb.Append( $"> **`Mods with FileSwaps: `** {ModManager.Count( m => m.TotalSwapCount > 0 )}, Total: {ModManager.Sum( m => m.TotalSwapCount )}\n" ); + sb.Append( $"> **`Mods with Meta Manipulations:`** {ModManager.Count( m => m.TotalManipulations > 0 )}, Total {ModManager.Sum( m => m.TotalManipulations )}\n" ); + sb.Append( $"> **`IMC Exceptions Thrown: `** {ImcExceptions.Count}\n" ); + sb.Append( $"> **`#Temp Mods: `** {TempMods.Mods.Sum( kvp => kvp.Value.Count ) + TempMods.ModsForAllCollections.Count}\n" ); string CharacterName( ActorIdentifier id, string name ) { if( id.Type is IdentifierType.Player or IdentifierType.Owned ) { - return string.Join( " ", name.Split( ' ', 3 ).Select( n => $"{n[ 0 ]}." ) ) + ':'; + var parts = name.Split( ' ', 3 ); + return string.Join( " ", parts.Length != 3 ? parts.Select( n => $"{n[ 0 ]}." ) : parts[ ..2 ].Select( n => $"{n[ 0 ]}." ).Append( parts[2] ) ); } return name + ':'; } void PrintCollection( ModCollection c ) - => sb.AppendFormat( "**Collection {0}**\n" - + "> **`Inheritances: `** {1}\n" - + "> **`Enabled Mods: `** {2}\n" - + "> **`Total Conflicts: `** {3}\n" - + "> **`Solved Conflicts: `** {4}\n", - c.AnonymizedName, c.Inheritance.Count, c.ActualSettings.Count( s => s is { Enabled: true } ), - c.AllConflicts.SelectMany( x => x ).Sum( x => x.HasPriority ? 0 : x.Conflicts.Count ), - c.AllConflicts.SelectMany( x => x ).Sum( x => x.HasPriority || !x.Solved ? 0 : x.Conflicts.Count ) ); + => sb.Append( $"**Collection {c.AnonymizedName}**\n" + + $"> **`Inheritances: `** {c.Inheritance.Count}\n" + + $"> **`Enabled Mods: `** {c.ActualSettings.Count( s => s is { Enabled: true } )}\n" + + $"> **`Conflicts (Solved/Total): `** {c.AllConflicts.SelectMany( x => x ).Sum( x => x.HasPriority ? 0 : x.Conflicts.Count )}/{c.AllConflicts.SelectMany( x => x ).Sum( x => x.HasPriority || !x.Solved ? 0 : x.Conflicts.Count )}\n" ); sb.AppendLine( "**Collections**" ); - sb.AppendFormat( "> **`#Collections: `** {0}\n", CollectionManager.Count - 1 ); - sb.AppendFormat( "> **`Active Collections: `** {0}\n", CollectionManager.Count( c => c.HasCache ) ); - sb.AppendFormat( "> **`Base Collection: `** {0}\n", CollectionManager.Default.AnonymizedName ); - sb.AppendFormat( "> **`Interface Collection: `** {0}\n", CollectionManager.Interface.AnonymizedName ); - sb.AppendFormat( "> **`Selected Collection: `** {0}\n", CollectionManager.Current.AnonymizedName ); + sb.Append( $"> **`#Collections: `** {CollectionManager.Count - 1}\n" ); + sb.Append( $"> **`#Temp Collections: `** {TempMods.CustomCollections.Count}\n" ); + sb.Append( $"> **`Active Collections: `** {CollectionManager.Count( c => c.HasCache )}\n" ); + sb.Append( $"> **`Base Collection: `** {CollectionManager.Default.AnonymizedName}\n" ); + sb.Append( $"> **`Interface Collection: `** {CollectionManager.Interface.AnonymizedName}\n" ); + sb.Append( $"> **`Selected Collection: `** {CollectionManager.Current.AnonymizedName}\n" ); foreach( var (type, name, _) in CollectionTypeExtensions.Special ) { var collection = CollectionManager.ByType( type ); if( collection != null ) { - sb.AppendFormat( "> **`{0,-29}`** {1}\n", name, collection.AnonymizedName ); + sb.Append( $"> **`{name,-30}`** {collection.AnonymizedName}\n" ); } } foreach( var (name, id, collection) in CollectionManager.Individuals.Assignments ) { - sb.AppendFormat( "> **`{1,-29}`** {0}\n", collection.AnonymizedName, CharacterName( id[ 0 ], name ) ); + sb.Append( $"> **`{CharacterName( id[ 0 ], name ),-30}`** {collection.AnonymizedName}\n" ); } foreach( var collection in CollectionManager.Where( c => c.HasCache ) ) diff --git a/Penumbra/UI/ConfigWindow.Changelog.cs b/Penumbra/UI/ConfigWindow.Changelog.cs index ea677f6c..a5f6204a 100644 --- a/Penumbra/UI/ConfigWindow.Changelog.cs +++ b/Penumbra/UI/ConfigWindow.Changelog.cs @@ -24,10 +24,38 @@ public partial class ConfigWindow Add5_10_0( ret ); Add5_11_0( ret ); Add5_11_1( ret ); + Add6_0_0( ret ); return ret; } + private static void Add6_0_0( Changelog log ) + => log.NextVersion( "Version 0.6.0.0" ) + .RegisterEntry( "Revamped Individual Collections:" ) + .RegisterEntry( "You can now specify individual collections for players (by name) of specific worlds or any world.", 1 ) + .RegisterEntry( "You can also specify NPCs (by grouped name and type of NPC), and owned NPCs (by specifying an NPC and a Player).", 1 ) + .RegisterHighlight( + "Migration should move all current names that correspond to NPCs to the appropriate NPC group and all names that can be valid Player names to a Player of any world.", + 1 ) + .RegisterHighlight( + "Please look through your Individual Collections to verify everything migrated correctly and corresponds to the game object you want. You might also want to change the 'Player (Any World)' collections to your specific homeworld.", + 1 ) + .RegisterEntry( "You can also manually sort your Individual Collections by drag and drop now.", 1 ) + .RegisterEntry( "This new system is a pretty big rework, so please report any discrepancies or bugs you find.", 1 ) + .RegisterEntry( "These changes made the specific ownership settings for Retainers and for preferring named over ownership obsolete.", 1 ) + .RegisterEntry( "General ownership can still be toggled and should apply in order of: Owned NPC > Owner (if enabled) > General NPC.", 1 ) + .RegisterEntry( "Added Dye Previews for in-game dyes and dyeing templates in Material Editing." ) + .RegisterEntry( "Added Export buttons to .mdl and .mtrl previews in Advanced Editing." ) + .RegisterEntry( "Collection selectors can now be filtered by name." ) + .RegisterEntry( "Try to use Unicode normalization before replacing invalid path symbols on import for somewhat nicer paths." ) + .RegisterEntry( "Improved interface for group settings (minimally)." ) + .RegisterEntry( "Prevent a bug that allowed IPC to add Mods from outside the Penumbra root folder." ) + .RegisterEntry( "Improved Support Info somewhat." ) + .RegisterEntry( "Fixed a bug when dragging options during mod edit." ) + .RegisterEntry( "Fixed a bug where sometimes the valid folder check caused issues." ) + .RegisterEntry( "Fixed a bug where the /penumbra enable/disable command displayed the wrong message (functionality unchanged)." ) + .RegisterEntry( "A lot of big backend changes." ); + private static void Add5_11_1( Changelog log ) => log.NextVersion( "Version 0.5.11.1" ) .RegisterEntry( diff --git a/Penumbra/UI/ConfigWindow.SettingsTab.General.cs b/Penumbra/UI/ConfigWindow.SettingsTab.General.cs index cc46d52a..a1aee0e4 100644 --- a/Penumbra/UI/ConfigWindow.SettingsTab.General.cs +++ b/Penumbra/UI/ConfigWindow.SettingsTab.General.cs @@ -63,28 +63,20 @@ public partial class ConfigWindow Penumbra.Config.HideRedrawBar, v => Penumbra.Config.HideRedrawBar = v ); ImGui.Dummy( _window._defaultSpace ); Checkbox( $"Use {AssignedCollections} in Character Window", - "Use the character collection for your characters name or the Your Character collection in your main character window, if it is set.", + "Use the individual collection for your characters name or the Your Character collection in your main character window, if it is set.", Penumbra.Config.UseCharacterCollectionInMainWindow, v => Penumbra.Config.UseCharacterCollectionInMainWindow = v ); Checkbox( $"Use {AssignedCollections} in Adventurer Cards", - "Use the appropriate character collection for the adventurer card you are currently looking at, based on the adventurer's name.", + "Use the appropriate individual collection for the adventurer card you are currently looking at, based on the adventurer's name.", Penumbra.Config.UseCharacterCollectionsInCards, v => Penumbra.Config.UseCharacterCollectionsInCards = v ); Checkbox( $"Use {AssignedCollections} in Try-On Window", - "Use the character collection for your character's name in your try-on, dye preview or glamour plate window, if it is set.", + "Use the individual collection for your character's name in your try-on, dye preview or glamour plate window, if it is set.", Penumbra.Config.UseCharacterCollectionInTryOn, v => Penumbra.Config.UseCharacterCollectionInTryOn = v ); Checkbox( $"Use {AssignedCollections} in Inspect Windows", - "Use the appropriate character collection for the character you are currently inspecting, based on their name.", + "Use the appropriate individual collection for the character you are currently inspecting, based on their name.", Penumbra.Config.UseCharacterCollectionInInspect, v => Penumbra.Config.UseCharacterCollectionInInspect = v ); Checkbox( $"Use {AssignedCollections} based on Ownership", - "Use the owner's name to determine the appropriate character collection for mounts, companions and combat pets.", + "Use the owner's name to determine the appropriate individual collection for mounts, companions, accessories and combat pets.", Penumbra.Config.UseOwnerNameForCharacterCollection, v => Penumbra.Config.UseOwnerNameForCharacterCollection = v ); - Checkbox( "Prefer Named Collections over Ownership", - "If you have a character collection set to a specific name for a companion or combat pet, prefer this collection over the owners collection.\n" - + "That is, if you have a 'Topaz Carbuncle' collection, it will use this one instead of the one for its owner.", - Penumbra.Config.PreferNamedCollectionsOverOwners, v => Penumbra.Config.PreferNamedCollectionsOverOwners = v ); - Checkbox( $"Use {DefaultCollection} for Housing Retainers", - $"Housing Retainers use the name of their owner instead of their own, you can decide to let them use their owners character collection or the {DefaultCollection}.\n" - + "It is not possible to make them have their own collection, since they have no connection to their actual name.", - Penumbra.Config.UseDefaultCollectionForRetainers, v => Penumbra.Config.UseDefaultCollectionForRetainers = v ); ImGui.Dummy( _window._defaultSpace ); DrawFolderSortType(); DrawAbsoluteSizeSelector(); diff --git a/Penumbra/UI/ConfigWindow.SettingsTab.cs b/Penumbra/UI/ConfigWindow.SettingsTab.cs index ab14c749..3a251e23 100644 --- a/Penumbra/UI/ConfigWindow.SettingsTab.cs +++ b/Penumbra/UI/ConfigWindow.SettingsTab.cs @@ -85,6 +85,11 @@ public partial class ConfigWindow { static bool IsSubPathOf( string basePath, string subPath ) { + if( basePath.Length == 0 ) + { + return false; + } + var rel = Path.GetRelativePath( basePath, subPath ); return rel == "." || !rel.StartsWith( '.' ) && !Path.IsPathRooted( rel ); }